Project Goal π―
In this article, we demonstrate how to convert documentation given as a Postman Collection (that is hosted online) to a Swagger formatted documentation (OpenAPI Specification), that is real-time updated according to the Postman Collection given in the beginning.
To visualize and interact with the documentation we use Swagger UI.
The technology the project is based on is Node.js.
Besides the differences in the User Interface and the basic features between Swagger UI and Postman, there is another reason why we might want to use the former tool.
At the time of writing, a Postman link is only a snapshot of your collection and you need to create a new link for the most up to date version (source Postman Docs). At least that is what is true about the free version, while there might be a solution to this limitation using Postman's Pro API (https://support.postman.com/hc/en-us/articles/212510625-How-do-my-team-members-update-a-collection-link-that-I-created-).
With our implementation, if you are provided with a stable URL for accessing the documentation, you can always have the most up-to-date view of the API docs on Swagger UI, using only Node.js.
Specific Application π©
The idea for this project was born from studying the API documentation of skroutz.gr, a Comparison Shopping Engine and e-commerce marketplace.
The API was given in JSON as a Postman collection in the following link.
So what we wanted to achieve was:
- to be able to visualize the documentation using Swagger UI
- our Swagger UI documentation to be updated periodically according to the JSON Postman collection that skroutz.gr initially provided (see here)
Packages π¦
Shortly, the packages we used for this project are:
- express - a minimalist web framework for node
- nodemon - automatically restarts the node application when files change in the directory
- swagger-ui-express - serves swagger-ui generated API docs from express
- node-fetch - a module to make HTTP requests
- fs - access and interaction with the file system
- api-spec-transformer - helps to convert between different API specifications
- yamljs - a JavaScript YAML Parser & Encoder
- dotenv-safe - ensures that all necessary environment variables are defined
Let's see some code π±βπ»
As a beginner in Node.js myself, I advise you, if you are not aware of it, to study first a bit how Async Programming works in this particular programming language (suggested material: https://blog.risingstack.com/node-hero-async-programming-in-node-js/).
As you can see below, in our app.js file, we used the express package for our API framework and the swagger-ui-express package to produce API docs from express, based on a swagger.json or swagger.yaml file type.
const express = require("express");
const swaggerUi = require("swagger-ui-express");
const ymlfile = require("./documentation")
const app = express();
// load env variables and create .env.example file
const dotenv_safe = require("dotenv-safe");
dotenv_safe.config();
// middleware
app.use('/api', swaggerUi.serve, swaggerUi.setup(ymlfile));
// listening on environment port if defined or 8080
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log(`Node JS API is listening on port: ${port}`);
});
In our other JS file, documentation.js, is where we create our ymlfile, which we give as an input to swaggerUi in app.js.
First, we need to query (fetch) periodically the URL where the JSON formatted API documentation is and store it locally into a JSON file. We do this with our createJSONFile async function:
const fetch = require('node-fetch');
const fs = require('fs').promises;
const transformer = require('api-spec-transformer');
const YAML = require('yamljs');
// set a timeout so that we can periodically query the website where the JSON formatted API documentation is
// currently set at 6 hours
setTimeout(createJSONFile, 21600)
async function createJSONFile() {
try {
console.log("ORDER OF EXECUTION: 7")
const response = await fetch('https://developer.skroutz.gr/assets/misc/skroutz_postman_collection.json')
const json = await response.json()
await fs.writeFile("./docs/skroutz_api.json", JSON.stringify(json));
console.log("The JSON file was saved!");
} catch (error) {
console.log(error.response.body);
}
console.log("ORDER OF EXECUTION: 8")
};
After that, we convert the JSON/Postman formatted file of the documentation to the YAML/OpenAPI Specification/Swagger format and store it locally, while also creating ymlfile.
(async function createYAMLFile() {
const autoToSwagger = new transformer.Converter(transformer.Formats.AUTO, transformer.Formats.SWAGGER);
console.log("ORDER OF EXECUTION: 1")
autoToSwagger.loadFile("./docs/skroutz_api.json", function(err) {
if (err) {
console.log(err.stack);
return;
}
console.log("ORDER OF EXECUTION: 4")
autoToSwagger.convert('yaml')
.then(function(convertedData) {
// convertedData is a swagger YAML string
// console.log(convertedData);
console.log("ORDER OF EXECUTION: 6")
fs.writeFile("./docs/skroutz_api.yaml", convertedData, function(err) {
if(err) {
return console.log(err);
}
});
console.log("The YAML file was saved!");
})
.catch(function(err){
console.log(err);
});
console.log("ORDER OF EXECUTION: 5")
});
console.log("ORDER OF EXECUTION: 2")
})();
console.log("ORDER OF EXECUTION: 3")
const ymlfile = YAML.load('./docs/skroutz_api.yaml');
module.exports = ymlfile
Finally, in order to avoid using anything else but Node.js we do a little trick to always keep the Swagger UI dynamically up to date. In the scripts in our package.json file, we use the nodemon package to start our application, since every time a file changes locally nodemon restarts the server. Otherwise, even if our JSON and YAML files were updated, their latest version would not be served by our /api route. As another possible solution, check out "Modify swagger file on the fly before load" at https://www.npmjs.com/package/swagger-ui-express.
In package.json:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "npm install",
"start": "nodemon app.js",
"dev": "nodemon app.js"
},
Some useful reads:
- Three Ways to Retrieve JSON from the Web using Node.js
- 5 Ways to Make HTTP Requests in Node.js using Async/Await
- Node.js Async Best Practices & Avoiding the Callback Hell
Running the project βοΈ
You can find all the above code on the project's GitHub:
KAUTH / Swagger-Skroutz-API
The Skroutz API documented live with Swagger UI
In order to run the project, first, clone the repository from GitHub, e.g.
git clone https://github.com/KAUTH/Swagger-Skroutz-API.git
To run this project locally you need to have npm installed.
When deploying the project for the first time, install all the required packages by running the
npm install
command on a terminal in the root directory.
After that, to run the project, use the
npm start
command.
The Swagger UI API documentation will then be accessible from http://localhost:8080/api/.
Important: There is 1 .env file (with environment variables) that our project uses, which is not on the repository for security reasons (as a best practice). In order for the project to run properly, you have to create your .env file in the same directory (root directory) that the .env.example file (example of how our .env file looks like) is present in this repository.
Enjoy π
The project is deployed with Heroku and can be found online at http://bit.ly/swagger-skroutz.
Thanks for reading, leave a like β€οΈπ¦π if you found the article interesting and of course your feedback π!
Top comments (1)
Hi Kostas,
Nice and useful guide, thank you very much.
This link is broken developer.skroutz.gr/assets/misc/s...
Do you have any other valid link to a postam collection. please?
Thanks.