“This article is participating in the technical topic essay node.js advanced road, click to see details”

In modern WEB development, data interaction is the main requirement, so for the front and back end data interaction, REST API is one of the data interaction design, how to design REST API? API design is critical to API experience. The quality of API design directly affects the development efficiency, so I won’t go into details here. If you are interested in API design, you can refer to the column “Preaching API”.

This article describes how to build API services using Node.js, MongoDB, Fastify, and Swagger.

The project source code address: github.com/QuintionTan…

Prior to the start

The technical framework needed is as follows:

  • Fastify: a fast and low-cost Web framework for Node.js;
  • MongooseElegant:mongodbObject modeling framework;
  • Swagger: One of the most widely used open source toolsets for developing apis using the OpenAPI specification.

Environment to be installed:

  • Node.js/ NPM: development run environment;
  • MongoDB: open source, high-performance NoSQL database, support for indexing, clustering, replication and failover, a variety of language drivers, high scalability;
  • Postman: is a powerful web debugging and sending HTTP requests developed by Google. It is often used to simulate or test back-end apis.

Begin to build

Open the create project directory mkdir restful- API on the terminal, go to the create code folder mkdir SRC, and then go to the SRC directory to create the file index.js.

Go back to the project root directory and initialize the project NPM init. When you’re done, a package.json file will be generated in the project directory.

Next, install the required dependencies:

npm install nodemon mongoose fastify fastify-swagger boom --save
Copy the code

The following is a brief introduction to the dependency packages for installation, all from the official introduction:

nodemon

Node.js is a tool that automatically restarts Node.js application services by detecting file changes in the directory, reducing the need for manual restarts.

Nodemon does not need to make any additional changes to the code or development logic, just change the project startup mode and modify the package.json file as follows:

"dev": "nodemon --trace-warnings ./src/index.js",
Copy the code

Mongoose

Mongoose provides a straightforward, pattern-based solution for modeling application data. It includes built-in type conversions, validation, query building, business logic hooks, and more, right out of the box.

Fastify

Fastify is a Web framework that is highly focused on providing the best developer experience with minimal overhead and a powerful plug-in architecture. Inspired by Hapi and Express, it is one of the fastest Web frameworks out there.

fastify-swagger

Fastify’s Swagger document generator, which uses patterns declared in routing to generate Swagger compliant documents.

boom

Boom provides a set of utilities for returning HTTP errors.

Start the service and create the route

Open the file SRC /index.js and add the following code:

const fastify = require("fastify")({ logger: true, }); // Define the route fastify. Get ("/", async (request, reply) => {return {message: "Hello Restful Api"}; }); // Start service const start = async () => {try {await fastify.listen(8100); Fastify.log.info (' service run port: ${fastify.server.address().port} '); } catch (err) { fastify.log.error(err); process.exit(1); }}; start();Copy the code

Introduce the Fastify framework, declare the first route for the project, and define the service run port 8100. Initialize Fastify with the built-in Logger enabled, which is disabled by default.

const fastify = require("fastify")({
    logger: true,
});
Copy the code

You can now run the following code in the terminal’s project root directory:

npm run dev
Copy the code

Open the browser and enter http://127.0.0.1:8100/. The following information is displayed:

{"message":"Hello Restful Api"}
Copy the code

Next, set up the MongoDB database.

Start MongoDB and create the model

After MongoDB is successfully installed, you can open a new terminal window and start the MongoDB instance by running the following command:

mongod
Copy the code

With MongoDB, there is no need to create a database. You can specify a name in your Settings, and MongoDB will create the database once the data is stored.

Open the file SRC /index.js and add the following code:

const mongoose = require("mongoose"); / / connect to the database mongoose. Connect (" mongo: / / localhost/crayon - restful - service "), then (() = > console. The log (" mongo has connection ")) .catch((err) => console.log(err));Copy the code

In the above code, use Mongoose to create and connect to the MongoDB database, named Crayon-resting-Service, and if all goes well, you will see MongoDB connected in the terminal.

With the database up and running, you can create the first data model for your project. Create the folder models in the SRC directory and create the coffee.js file in it and add the following code:

const { Schema, model } = require("mongoose");

const coffeeSchema = new Schema({
    title: String,
    ratio: String,
    cup: String,
    description: String,
});

module.exports = model("Coffee", coffeeSchema);
Copy the code

The above code declares coffeeSchema, which contains the basic information related to Coffee, and then exports coffeeSchema for use in later applications.

Creating a Controller

Create a folder named controllers in the SRC directory and create the file coffeecontroller.js as follows:

const boom = require("boom"); Models const Coffee = require(".. /models/Coffee"); // Get all Coffees exports.getList = async (req, res) => {try {const Coffees = await coffee.find (); return coffees; } catch (err) { throw boom.boomify(err); }}; Get = async (req, res) => {try {const ID = req.params.id; // Get a single Coffee message exports.get = async (req, res) => {try {const ID = req.params.id; const coffee = await Coffee.findById(id); return coffee; } catch (err) { throw boom.boomify(err); }}; // new exports.add = async (req, res) => {try {const coffee = new coffee (req.body); return coffee.save(); } catch (err) { throw boom.boomify(err); }}; // update exports. Update = async (req, res) => {try {const id = req.params.id; const coffee = req.body; const { ... updateData } = coffee; const update = await Coffee.findByIdAndUpdate(id, updateData, { new: true, }); return update; } catch (err) { throw boom.boomify(err); }}; // delete exports.delete = async (req, res) => {try {const id = req.params.id; const coffee = await Coffee.findByIdAndRemove(id); return coffee; } catch (err) { throw boom.boomify(err); }};Copy the code

The above code looks a bit much, but it’s really just CURD simplicity for the database.

  • All exceptions are handed overboomTo deal with:boom.boomify(err).
  • Each function is an asynchronous function and can contain oneawaitExpression that suspends the execution of an asynchronous function and waits for the result to passPromiseTo parse and return the parsed value.
  • Each function is included in thetry/catchIn the statement.
  • Each function takes two arguments:req(Request) andres(Response).

Create and import routes

Create folder routes and create file index.js in SRC. Add the following code:

const coffeeController = require(".. /controllers/coffeeController"); const APIPATH = "/api/"; const VERSION = "v1"; const ENDPOINT = "/coffees"; const getFullPath = (method = "") => `${APIPATH}${VERSION}${ENDPOINT}${method}`; const routes = [ { method: "GET", url: getFullPath(), handler: coffeeController.getList, }, { method: "GET", url: getFullPath("/:id"), handler: coffeeController.get, }, { method: "POST", url: getFullPath(), handler: coffeeController.add, }, { method: "PUT", url: getFullPath("/:id"), handler: coffeeController.update, }, { method: "DELETE", url: getFullPath("/:id"), handler: coffeeController.delete, }, ]; module.exports = routes;Copy the code

The code above defines the interface route and sets its controller methods. Each route consists of a method, a URL, and a handler handler that configures which controller method the application uses when accessing one of the routes.

For some routes :id is a common way to pass parameters to the route. You can pass the parameter ID as follows:

http://127.0.0.1:8100/api/v1/coffees/6235a1b03797442599fb6fc7
Copy the code

Creating API documentation

A good API service requires complete documentation, which used to be written by hand, but these things can now be done with tools. This article will use Swagger to support documentation.

Create folder config in SRC directory and create file swagger.js in SRC directory. Add the following code:

exports.options = { routePrefix: "/api/v1/helper", exposeRoute: true, swagger: { info: { title: Use Node.js, MongoDB, Fastify, and Swagger to build Restful apis for Coffee. }, stripBasePath: true, host: "localhost", basePath: "/ API /v1", externalDocs: {url: "https://swagger.io", description: "More information ",}, substitution: [" HTTP "], Consumes: ["application/json"], Produces: ["application/json"], }, };Copy the code

The code above is a simple configuration for Swagger, and to pass it to the fastify-Swagger plug-in, add the following to the SRC /index.js file:

const swagger = require("./config/swagger");
Copy the code

Then add the following code to the Fastify definition as follows:

const fastify = require("fastify")({
    logger: true,
});

fastify.register(require("fastify-swagger"), swagger.options);
Copy the code

Next, you need to add the following code after initializing the Fastify server:

await fastify.listen(8100);
fastify.swagger();
Copy the code

Now open http://localhost:8100/api/v1/helper in the browser, you can see the following content:

As shown in the figure above, the interface does not have any description. You need to add detailed interface description information.

Create folder docs in SRC and create file coffess.js, add the following code:

const coffeeBody = { type: "object", properties: { _id: { type: "string" }, title: { type: "string", description: "Type name"}, ratio: {type: "string"}, cup: {type: "string"}, description: {type: "string"}, __v: {type: "string"}, "number" }, }, }; Exports.coffeesschema = {list: {description: "Get a list of coffee types ", tags: ["coffees"], summary:" Get a list of all coffee types ", response: {200: Description: ["coffees"], tags: ["coffees"], summary: Querystring: {type: "object", properties: {id: {type: "string",},},}, response: {200: {description: "Succeeded ",... CoffeeBody,},},} add: {description: "Create a new type of coffee ", tags: ["coffees"], summary:" Add a new type of coffee ", body: {... CoffeeBody,}, response: {200: {description: "Created successfully ",... CoffeeBody,},},}, update: {description: "Update coffee type details ", tags: ["coffees"], summary:" Update coffee type details by ID ", QueryString: { type: "object", properties: { id: { type: "string", }, }, }, body: { ... CoffeeBody,}, response: {200: {description: "Update successful ",... CoffeeBody,},},}, delete: {description: "Delete coffee type details ", tags: ["coffees"], summary:" Delete coffee type details by ID ", QueryString: {type: "object", properties: {id: {type: "string",},},}, Response: {200: {description: "deleted ", type: "string", }, }, }, };Copy the code

Change the file routes/index.js and import the API file as follows:

const { coffeesSchema } = require(".. /docs/coffees");Copy the code

Then modify each route, add attribute schema, open the document page again, the effect is as follows:

Test the API

Now that you’ve built most of the modules, you just need to wire them together and start interacting with data through API offerings.

First, add the following code to the SRC /index.js file to import the routing information:

const routes = require("./routes");
Copy the code

You then need to initialize it with the Fastify traversal routes array, adding the following code to the SRC /index.js file:

routes.forEach((route, index) => {
    fastify.route(route);
});
Copy the code

At this point, a simple REST API service is complete and ready to test!

The best tool for testing apis is Postman, which simulates API data for testing.

The new data

To obtain a list of

For more details

The deployment of

Node.js builds services that can be started by pM2 or deployed by Docker. We will not expand the description here, but recommend two related contents:

  • Docker for WEB Developers
  • PM2 Practical Guide and Container Docker Deployment

conclusion

At this point, a complete REST API has been built, just a simple example that can be used as a foundation for node.js back-end services on which to iterate on richer services. At present, the instance does not add verification rules of Model field, pagination of list and other complex logic, and can continue to iterate. The process of creating directories in this article can be completed automatically during the initialization of the project by building scaffolding plug-in.