]> BookStack Code Mirror - api-scripts/blob - node-generate-postman-collection/index.js
Update README.md
[api-scripts] / node-generate-postman-collection / index.js
1 // Libraries used
2 const axios = require('axios');
3
4 // BookStack API variables
5 // Uses values on the environment unless hardcoded
6 // To hardcode, add values to the empty strings in the below.
7 const bookStackConfig = {
8     base_url: '' || process.env.BS_URL,
9     token_id: '' || process.env.BS_TOKEN_ID,
10     token_secret: '' || process.env.BS_TOKEN_SECRET,
11 };
12
13 // Script Logic
14 ////////////////
15
16 // Create an axios instance for our API
17 const api = axios.create({
18     baseURL: bookStackConfig.base_url.replace(/\/$/, '') + '/api/',
19     timeout: 5000,
20     headers: {'Authorization': `Token ${bookStackConfig.token_id}:${bookStackConfig.token_secret}`},
21 });
22
23 // Wrap the rest of our code in an async function, so we can await within.
24 (async function () {
25
26     // Get our default schema structure and look up to BookStack
27     // to get a JSON view of the BookStack docs.
28     const postmanSchema = getBaseCollectionSchema();
29     const {data: docs} = await api.get('/docs.json');
30
31     // Cycle over the endpoint categories within the API docs
32     for (const [category, endpoints] of Object.entries(docs)) {
33         // Create the schema for the postman collection, which represents
34         // a BookStack API category.
35         const postmanFolderSchema = {
36             name: category.toUpperCase(),
37             item: [],
38         };
39
40         // Cycle over the endpoints within the category
41         for (const endpoint of endpoints) {
42             postmanFolderSchema.item.push(getEndpointSchema(endpoint));
43         }
44
45         // Push our endpoint data into the postman collection
46         postmanSchema.item.push(postmanFolderSchema);
47     }
48
49     // Output the postman collection data to the command line
50     console.log(JSON.stringify(postmanSchema, null, 2));
51
52 })().catch(err => {
53
54     // Handle API errors
55     if (err.response) {
56         console.error(`Request failed with status ${err.response.status} [${err.response.statusText}]`);
57         return;
58     }
59
60     // Output all other errors
61     console.error(err)
62 });
63
64
65 /**
66  * Get the postman collection data for a specific endpoint.
67  * @param {Object} apiEndpoint
68  * @return {{request: {method, header: *[]}, response: *[], name: string}}
69  */
70 function getEndpointSchema(apiEndpoint) {
71     // Create our base format for the postman schema for a single endpoint
72     const postmanEndpointSchema = {
73         name: `${apiEndpoint.name}`,
74         request: {
75             method: apiEndpoint.method,
76             header: [],
77         },
78         response: []
79     };
80
81     // Create the base format used to represent a URL
82     const url = {
83         raw: `{{BASE_URL}}/${apiEndpoint.uri}`,
84         host: ['{{BASE_URL}}'],
85         path: apiEndpoint.uri.split('/'),
86         query: []
87     };
88
89     // If a listing endpoint, add the standard list params,
90     // although we leave them disabled by default.
91     if (apiEndpoint.controller_method === 'list') {
92         url.query = [
93             {
94                 "key": "count",
95                 "value": "100",
96                 "disabled": true
97             },
98             {
99                 "key": "offset",
100                 "value": "0",
101                 "disabled": true
102             },
103             {
104                 "key": "sort",
105                 "value": "+name",
106                 "disabled": true
107             },
108             {
109                 "key": "filter[id]",
110                 "value": "5",
111                 "disabled": true
112             }
113         ];
114     }
115
116     // Add the url to the request schema
117     postmanEndpointSchema.request.url = url;
118
119     // Build a description for the endpoint
120     // Formats the body parameters, if existing, to shown their validations.
121     const description = [apiEndpoint.description];
122     if (apiEndpoint.body_params) {
123         description.push('', '', 'Available body parameters:', '');
124         for (const [name, validations] of Object.entries(apiEndpoint.body_params)) {
125             description.push(`${name}: ${validations.join(' :: ')}`);
126         }
127     }
128     postmanEndpointSchema.request.description = description.join('\n');
129
130     // If we have an example request, push it as default body JSON data
131     if (apiEndpoint.example_request) {
132         postmanEndpointSchema.request.header.push({
133             "key": "Content-Type",
134             "value": "application/json"
135         });
136         postmanEndpointSchema.request.body = {
137             mode: "raw",
138             raw: apiEndpoint.example_request,
139             options: {
140                 raw: {
141                     language: 'json'
142                 }
143             }
144         }
145     }
146
147     // Push an example of a response if we have one
148     if (apiEndpoint.example_response) {
149         postmanEndpointSchema.response.push({
150             name: 'Example Response',
151             "status": "OK",
152             "code": 200,
153             "_postman_previewlanguage": "json",
154             header: [
155                 {
156                     "key": "Content-Type",
157                     "value": "application/json"
158                 },
159             ],
160             body: apiEndpoint.example_response,
161         });
162     }
163
164     // Provide back the postman schema data
165     return postmanEndpointSchema;
166 }
167
168 /**
169  * Get the base Postman collection schema data structure.
170  * Contains auth data and variables.
171  * @return {{item: *[], auth: {apikey: [{type: string, value: string, key: string},{type: string, value: string, key: string}], type: string}, variable: [{type: string, value: string, key: string},{type: string, value: string, key: string},{type: string, value: string, key: string}], event: [{listen: string, script: {type: string, exec: string[]}},{listen: string, script: {type: string, exec: string[]}}], info: {schema: string, name: string}}}
172  */
173 function getBaseCollectionSchema() {
174     return {
175         info: {
176             name: "BookStack REST API",
177             schema: "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
178         },
179         item: [
180         ],
181         auth: {
182             type: "apikey",
183             apikey: [
184                 {
185                     key: "value",
186                     value: "Token {{TOKEN_ID}}:{{TOKEN_SECRET}}",
187                     type: "string"
188                 },
189                 {
190                     key: "key",
191                     value: "Authorization",
192                     type: "string"
193                 }
194             ]
195         },
196         event: [
197             {
198                 listen: "prerequest",
199                 script: {
200                     type: "text/javascript",
201                     exec: [
202                         ""
203                     ]
204                 }
205             },
206             {
207                 listen: "test",
208                 script: {
209                     type: "text/javascript",
210                     exec: [
211                         ""
212                     ]
213                 }
214             }
215         ],
216         variable: [
217             {
218                 key: "TOKEN_ID",
219                 value: "",
220                 type: "default"
221             },
222             {
223                 key: "TOKEN_SECRET",
224                 value: "",
225                 type: "default"
226             },
227             {
228                 key: "BASE_URL",
229                 value: "",
230                 type: "default"
231             }
232         ]
233     };
234 }