--- /dev/null
+// Libraries used
+const axios = require('axios');
+
+// BookStack API variables
+// Uses values on the environment unless hardcoded
+// To hardcode, add values to the empty strings in the below.
+const bookStackConfig = {
+ base_url: '' || process.env.BS_URL,
+ token_id: '' || process.env.BS_TOKEN_ID,
+ token_secret: '' || process.env.BS_TOKEN_SECRET,
+};
+
+// Script Logic
+////////////////
+
+// Create an axios instance for our API
+const api = axios.create({
+ baseURL: bookStackConfig.base_url.replace(/\/$/, '') + '/api/',
+ timeout: 5000,
+ headers: {'Authorization': `Token ${bookStackConfig.token_id}:${bookStackConfig.token_secret}`},
+});
+
+// Wrap the rest of our code in an async function, so we can await within.
+(async function () {
+
+ // Get our default schema structure and look up to BookStack
+ // to get a JSON view of the BookStack docs.
+ const postmanSchema = getBaseCollectionSchema();
+ const {data: docs} = await api.get('/docs.json');
+
+ // Cycle over the endpoint categories within the API docs
+ for (const [category, endpoints] of Object.entries(docs)) {
+ // Create the schema for the postman collection, which represents
+ // a BookStack API category.
+ const postmanFolderSchema = {
+ name: category.toUpperCase(),
+ item: [],
+ };
+
+ // Cycle over the endpoints within the category
+ for (const endpoint of endpoints) {
+ postmanFolderSchema.item.push(getEndpointSchema(endpoint));
+ }
+
+ // Push our endpoint data into the postman collection
+ postmanSchema.item.push(postmanFolderSchema);
+ }
+
+ // Output the postman collection data to the command line
+ console.log(JSON.stringify(postmanSchema, null, 2));
+
+})().catch(err => {
+
+ // Handle API errors
+ if (err.response) {
+ console.error(`Request failed with status ${err.response.status} [${err.response.statusText}]`);
+ return;
+ }
+
+ // Output all other errors
+ console.error(err)
+});
+
+
+/**
+ * Get the postman collection data for a specific endpoint.
+ * @param {Object} apiEndpoint
+ * @return {{request: {method, header: *[]}, response: *[], name: string}}
+ */
+function getEndpointSchema(apiEndpoint) {
+ // Create our base format for the postman schema for a single endpoint
+ const postmanEndpointSchema = {
+ name: `${apiEndpoint.name}`,
+ request: {
+ method: apiEndpoint.method,
+ header: [],
+ },
+ response: []
+ };
+
+ // Create the base format used to represent a URL
+ const url = {
+ raw: `{{BASE_URL}}/${apiEndpoint.uri}`,
+ host: ['{{BASE_URL}}'],
+ path: apiEndpoint.uri.split('/'),
+ query: []
+ };
+
+ // If a listing endpoint, add the standard list params,
+ // although we leave them disabled by default.
+ if (apiEndpoint.controller_method === 'list') {
+ url.query = [
+ {
+ "key": "count",
+ "value": "100",
+ "disabled": true
+ },
+ {
+ "key": "offset",
+ "value": "0",
+ "disabled": true
+ },
+ {
+ "key": "sort",
+ "value": "+name",
+ "disabled": true
+ },
+ {
+ "key": "filter[id]",
+ "value": "5",
+ "disabled": true
+ }
+ ];
+ }
+
+ // Add the url to the request schema
+ postmanEndpointSchema.request.url = url;
+
+ // Build a description for the endpoint
+ // Formats the body parameters, if existing, to shown their validations.
+ const description = [apiEndpoint.description];
+ if (apiEndpoint.body_params) {
+ description.push('', '', 'Available body parameters:', '');
+ for (const [name, validations] of Object.entries(apiEndpoint.body_params)) {
+ description.push(`${name}: ${validations.join(' :: ')}`);
+ }
+ }
+ postmanEndpointSchema.request.description = description.join('\n');
+
+ // If we have an example request, push it as default body JSON data
+ if (apiEndpoint.example_request) {
+ postmanEndpointSchema.request.header.push({
+ "key": "Content-Type",
+ "value": "application/json"
+ });
+ postmanEndpointSchema.request.body = {
+ mode: "raw",
+ raw: apiEndpoint.example_request,
+ options: {
+ raw: {
+ language: 'json'
+ }
+ }
+ }
+ }
+
+ // Push an example of a response if we have one
+ if (apiEndpoint.example_response) {
+ postmanEndpointSchema.response.push({
+ name: 'Example Response',
+ "status": "OK",
+ "code": 200,
+ "_postman_previewlanguage": "json",
+ header: [
+ {
+ "key": "Content-Type",
+ "value": "application/json"
+ },
+ ],
+ body: apiEndpoint.example_response,
+ });
+ }
+
+ // Provide back the postman schema data
+ return postmanEndpointSchema;
+}
+
+/**
+ * Get the base Postman collection schema data structure.
+ * Contains auth data and variables.
+ * @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}}}
+ */
+function getBaseCollectionSchema() {
+ return {
+ info: {
+ name: "BookStack REST API",
+ schema: "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
+ },
+ item: [
+ ],
+ auth: {
+ type: "apikey",
+ apikey: [
+ {
+ key: "value",
+ value: "Token {{TOKEN_ID}}:{{TOKEN_SECRET}}",
+ type: "string"
+ },
+ {
+ key: "key",
+ value: "Authorization",
+ type: "string"
+ }
+ ]
+ },
+ event: [
+ {
+ listen: "prerequest",
+ script: {
+ type: "text/javascript",
+ exec: [
+ ""
+ ]
+ }
+ },
+ {
+ listen: "test",
+ script: {
+ type: "text/javascript",
+ exec: [
+ ""
+ ]
+ }
+ }
+ ],
+ variable: [
+ {
+ key: "TOKEN_ID",
+ value: "",
+ type: "default"
+ },
+ {
+ key: "TOKEN_SECRET",
+ value: "",
+ type: "default"
+ },
+ {
+ key: "BASE_URL",
+ value: "",
+ type: "default"
+ }
+ ]
+ };
+}
\ No newline at end of file
--- /dev/null
+{
+ "name": "bookstack-generate-postman-collection",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "bookstack-generate-postman-collection",
+ "version": "1.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "axios": "^0.25.0"
+ }
+ },
+ "node_modules/axios": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
+ "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
+ "dependencies": {
+ "follow-redirects": "^1.14.7"
+ }
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.14.8",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
+ "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ }
+ },
+ "dependencies": {
+ "axios": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
+ "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
+ "requires": {
+ "follow-redirects": "^1.14.7"
+ }
+ },
+ "follow-redirects": {
+ "version": "1.14.8",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
+ "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
+ }
+ }
+}
--- /dev/null
+# Generate Postman Collection
+
+This script will scan the BookStack API documentation and generate
+out an importable collection for [Postman](https://www.postman.com/).
+
+**Note:** This has been built quite hastily so the output may not be
+100% accurate but should massively speed up most use-cases.
+
+[An example of the output can be found here](https://gist.githubusercontent.com/ssddanbrown/de805abfdf1a1defb54500055de5e7ea/raw/7ec246a4d140c98313f3bcda00e1bac6d9e68b68/bs.postman_collection.json).
+
+The output collection will contain a folder for each of the API categories.
+Collection variables are used to configure the API base url, token ID
+and token secret.
+
+## Requirements
+
+You will need NodeJS installed (Tested on v16, may work on earlier versions).
+
+## Running
+
+First, download all the files in the same directory as this readme to a folder on your system
+and run the below from within that directory.
+
+```bash
+# Install NodeJS dependencies via NPM
+npm install
+
+# Setup
+# ALTERNATIVELY: Open the script and add to the empty strings in the variables at the top.
+export BS_URL=https://bookstack.example.com # Set to be your BookStack base URL
+export BS_TOKEN_ID=abc123 # Set to be your API token_id
+export BS_TOKEN_SECRET=123abc # Set to be your API token_secret
+
+# Running the script
+node index.js
+```
+
+The script outputs stdout on the command line, so you'll most likely want to redirect the output to a file.
+
+## Examples
+
+```bash
+# Generate the collection to a 'bookstack.postman_collection.json' file.
+node index.js > bookstack.postman_collection.json
+```
\ No newline at end of file