DevGang
Авторизоваться

Документирование API Node.js с использованием Swagger

Документация по API является неотъемлемой частью разработки программного обеспечения. Это руководство по эксплуатации, в котором объясняется, как использовать API и его сервисы. Это руководство может содержать учебные пособия, примеры кода, скриншоты и все остальное, что поможет пользователям лучше понять, как работать с API.

В этой статье мы узнаем, как документировать API, написанный на Node.js используя инструмент под названием Swagger. Swagger позволяет вам описывать структуру ваших API-интерфейсов таким образом, чтобы машины могли их читать. Способность API описывать свою собственную структуру является корнем всего удивительного в Swagger. Почему это так здорово? Что ж, ознакомившись со структурой нашего API, swagger может автоматически создавать красивую и интерактивную документацию по API. Он также может автоматически генерировать клиентские библиотеки для вашего API на многих языках и исследовать другие возможности, такие как автоматическое тестирование. Swagger делает это, запрашивая наш API вернуть YAML или JSON, содержащий подробное описание всего вашего API. Этот файл, по сути, представляет собой список ресурсов нашего API, который соответствует спецификациям Open API.

Создание нашего API с помощью Node.js и Express

Чтобы начать писать спецификации API, мы создадим наш API с Node.js который представляет собой back-end выполнения JavaScript, которая работает на движке JavaScript V8 и выполняет код JavaScript вне веб-браузера. Для простоты мы настроили проект, и его можно клонировать из этого репозитория GitHub. Чтобы запустить серверную часть на вашем локальном компьютере, мы выполним следующие действия:

  • Создайте новую папку для проекта и запустите эту команду в корневой папке, чтобы клонировать репозиторий
git clone https://github.com/DesmondSanctity/node-js-swagger.git
  • Для успешного запуска кода нам потребуется подключение к базе данных. Мы использовали кластер MongoDB Atlas для базы данных, и мы можем следовать этому руководству, чтобы настроить его, это довольно просто настроить. После настройки мы получим наш URL-адрес, и это все, что нам нужно для подключения к нашей базе данных из нашего приложения.
  • Мы используем JSON Web Token (JWT) для аутентификации доступа к нашему API, поэтому мы создадим секретный ключ, который будет использоваться нашим приложением для отправки и проверки запросов. Чтобы сгенерировать это, мы запустим эту команду в любом месте нашего терминала. Этот скрипт сгенерирует случайную 64-битную строку ASCII, которую можно использовать для шифрования токенов JWT.
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
  • Теперь мы создадим файл с именем .env, в котором мы будем хранить URL-адрес нашего кластера MongoDB Atlas и секрет JWT в качестве переменной среды. Файл должен выглядеть так:
    JWT_SECRET=<your JWT secret>
    ATLAS_URI=<your MongoDB Atlas cluster URL>
  • Теперь мы готовы запустить приложение, но сначала мы установим несколько пакетов, а затем запустим приложение. Если вы ранее клонировали репозиторий GitHub, вам просто нужно выполнить следующие команды:
    npm install   // To install the neccessary packages
    npm start    //  To start the application
  • Если вы добились успеха на этом этапе, вы увидите следующее сообщение в своем терминале.
    > mini-blog@1.0.0 start
    > nodemon server.js

    [nodemon] 2.0.20
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): *.*
    [nodemon] watching extensions: js,mjs,json
    [nodemon] starting `node server.js`
    Database Connected
    Server connected to http://localhost:8080

Добавление пользовательского интерфейса и конфигураций Swagger

Теперь, когда у нас есть готовый API, мы начнем определять для них спецификации Swagger. Есть два способа создать документацию Swagger для нашего API:

  • Вручную напишите спецификации в файлах маршрутизатора или в специальном файле json или yaml в нашем приложении.
  • Использование существующих инструментов или пакетов разработчика для автоматического создания документации.

В этом руководстве мы будем использовать ручной подход, чтобы обеспечить точность наших определений и спецификаций. Сначала мы установим два пакета под названием «swagger-jsdoc» и «swagger-ui-express» в качестве зависимостей, используя эту команду:

npm install swagger-jsdoc swagger-ui-express --save-dev

После установки мы создадим новый файл с именем swagger.js в корневом каталоге нашего приложения и вставим в него следующий код.

    import swaggerJsdoc from 'swagger-jsdoc'
    import swaggerUi from 'swagger-ui-express'
    const options = {
      definition: {
        openapi: '3.0.0',
        info: {
          title: 'Mini Blog API',
          description: "API endpoints for a mini blog services documented on swagger",
          contact: {
            name: "Desmond Obisi",
            email: "info@miniblog.com",
            url: "https://github.com/DesmondSanctity/node-js-swagger"
          },
          version: '1.0.0',
        },
        servers: [
          {
            url: "http://localhost:8080/",
            description: "Local server"
          },
          {
            url: "<your live url here>",
            description: "Live server"
          },
        ]
      },
      // looks for configuration in specified directories
      apis: ['./router/*.js'],
    }
    const swaggerSpec = swaggerJsdoc(options)
    function swaggerDocs(app, port) {
      // Swagger Page
      app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
      // Documentation in JSON format
      app.get('/docs.json', (req, res) => {
        res.setHeader('Content-Type', 'application/json')
        res.send(swaggerSpec)
      })
    }
    export default swaggerDocs

Из кода, в котором мы определили спецификацию Open API (OAS), которую мы будем использовать для нашей документации, мы можем видеть: информацию или подробности об API, серверах, которым мы будем его предоставлять, и маршрутах в нашем приложении, где Swagger должен искать для спецификаций для каждого из наших API.

Мы также можем видеть нашу функцию swaggerDocs, которая позволяет экземпляру приложения и порту создавать документацию для использования пакетов swaggerUi и swaggerJsdoc, которые мы установили ранее, и обслуживать их по маршруту /docs. Мы также можем получить формат JSON, используя /docs.json. Наконец, мы обновим наш файл server.js, чтобы включить нашу функцию swaggerDocs, чтобы всегда генерировать и обновлять наши документы всякий раз, когда мы запускаем проект.

Последним шагом перед написанием спецификации для каждой конечной точки является добавление функции swaggerDocs в наш файл server.js, чтобы мы инициировали swagger при каждом запуске нашего приложения.

    import express from 'express';
    import cors from 'cors';
    import morgan from 'morgan';
    import dotenv from 'dotenv';
    import connect from './database/conn.js';
    import userRouter from './router/user.js';
    import postRouter from './router/post.js';
    import swaggerDocs from './swagger.js'

    dotenv.config()
    const app = express();
    /** middlewares */
    app.use(express.json());
    app.use(cors());
    app.use(morgan('tiny'));
    app.disable('x-powered-by'); // less hackers know about our stack

    const port = process.env.PORT || 8080;
    /** HTTP GET Request */
    app.get('/', (req, res) => {
        res.status(201).json("Home GET Request");
    });

    /** api routes */
    app.use('/api/user', userRouter)
    app.use('/api/post', postRouter)
    /** start server only when we have valid connection */
    connect().then(() => {
        try {
            app.listen(port, () => {
                console.log(`Server connected to http://localhost:${port}`);
            })
            swaggerDocs(app, port)
        } catch (error) {
            console.log('Cannot connect to the server')
        }
    }).catch(error => {
        console.log("Invalid database connection...!");
    })

Написание спецификаций API

Теперь перейдем к основной задаче: напишем спецификации для нашего API, которые Swagger будет использовать для создания документации для нас. В настоящее время у нас есть два контроллера и файлы маршрутизатора в нашем приложении для user и post. Наши контроллеры содержат логику для приложения, в то время как маршрутизатор передает конечную точку и полезную нагрузку контроллеру в виде запросов. Приступим к определению спецификации!

Для User маршрутизатора мы сначала импортируем необходимые пакеты в файл маршрутизатора user.js:

    import { Router } from "express";
    const userRouter = Router();
    /** import all controllers */
    import * as controller from '../controllers/userController.js';
    import Auth from '../middleware/auth.js';

    /** All the API routes comes here*/

    export default userRouter;

Затем мы напишем спецификацию для каждого типа запроса, а именно GET, POST, PUT и DELETE. Спецификация представляет собой файл yaml, встроенный в начало маршрута, который мы хотим задокументировать. Некоторые ключевые моменты, на которые следует обратить внимание:

  • Экземпляр спецификации Open API — записывается в начале файла yaml.
  • Конечная точка API — URL-адрес, который мы будем использовать для запроса.
  • Request Type — указывает, является ли это запросом GET, POST, PUT или DELETE.
  • Request Body — для передачи нашей полезной нагрузки в API.
  • Parameters — данные, которые мы передаем через URL или параметры в серверную часть.
  • Content Type — тип контента, который мы отправляем. Он передается в заголовок HTTP.
  • Schema — содержит тип нашего тела запроса, обязательные поля и свойства, которые может принимать тело запроса.
  • Response — результат сделанного нами вызова API, он сообщает нам, был ли он неудачным или успешным, а также сообщает об ошибках.

POST:

    /** POST Methods */
    /**
     * @openapi
     * '/api/user/register':
     *  post:
     *     tags:
     *     - User Controller
     *     summary: Create a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - username
     *              - email
     *              - password
     *            properties:
     *              username:
     *                type: string
     *                default: johndoe 
     *              email:
     *                type: string
     *                default: johndoe@mail.com
     *              password:
     *                type: string
     *                default: johnDoe20!@
     *     responses:
     *      201:
     *        description: Created
     *      409:
     *        description: Conflict
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/register').post(controller.register); // register user

    /**
     * @openapi
     * '/api/user/login':
     *  post:
     *     tags:
     *     - User Controller
     *     summary: Login as a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - username
     *              - password
     *            properties:
     *              username:
     *                type: string
     *                default: johndoe
     *              password:
     *                type: string
     *                default: johnDoe20!@
     *     responses:
     *      201:
     *        description: Created
     *      409:
     *        description: Conflict
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/login').post(controller.verifyUser,controller.login); // login in app

    /**
     * @openapi
     * '/api/user/verify':
     *  post:
     *     tags:
     *     - User Controller
     *     summary: Verify a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - username
     *            properties:
     *              username:
     *                type: string
     *                default: johndoe
     *     responses:
     *      201:
     *        description: Created
     *      409:
     *        description: Conflict
     *      404:
     *        description: Not Found
     *      500:
     *        desccription: Server Error
     */
    userRouter.route('/verify').post(controller.verifyUser, (req, res) => res.end()); // authenticate user

GET:

    /** GET Methods */
    /**
     * @openapi
     * '/api/user/{username}':
     *  get:
     *     tags:
     *     - User Controller
     *     summary: Get a user by username
     *     parameters:
     *      - name: username
     *        in: path
     *        description: The username of the user
     *        required: true
     *     responses:
     *      200:
     *        description: Fetched Successfully
     *      400:
     *        description: Bad Request
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/:username').get(controller.getUser) // user with username

PUT:

/** PUT Methods */
    /**
     * @openapi
     * '/api/user/update':
     *  put:
     *     tags:
     *     - User Controller
     *     summary: Modify a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - userId
     *            properties:
     *              userId:
     *                type: string
     *                default: ''
     *              firstName:
     *                type: string
     *                default: ''
     *              lastName:
     *                type: string
     *                default: ''
     *     responses:
     *      200:
     *        description: Modified
     *      400:
     *        description: Bad Request
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/update').put(controller.updateUser); // is use to update the user profile

DELETE:

/** DELETE Methods */
    /**
     * @openapi
     * '/api/user/{userId}':
     *  delete:
     *     tags:
     *     - User Controller
     *     summary: Delete user by Id
     *     parameters:
     *      - name: userId
     *        in: path
     *        description: The unique Id of the user
     *        required: true
     *     responses:
     *      200:
     *        description: Removed
     *      400:
     *        description: Bad request
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/:userId').delete(controller.deleteUser);

Тестирование наших API на Swagger

После завершения нашей документации API мы сможем просмотреть нашу документацию Swagger и протестировать наш API, используя ее. Если вы дошли до этого момента, у вас должно получиться изображение, подобное приведенному ниже. Наша документация обслуживается по маршруту /docs.

Мы сделаем несколько запросов, используя пользовательский интерфейс документации Swagger, и посмотрим на результаты.

Чтобы создать User:

Чтобы создать Post:

Как мы видели из приведенных выше примеров, мы можем использовать документацию Swagger для тестирования нашего API, для создания, чтения и изменения данных в нашей базе данных. Это помогает сделать API понятным и простым для интеграции другими. Следуя этим примерам, мы можем пойти дальше и протестировать другие методы запроса, такие как PUT для обновления пользователя или сообщения, GET для чтения пользователя или POST и DELETE для их удаления из базы данных.

Выводы

Наконец, мы можем сделать вывод, что документация по API является очень важной частью цикла разработки программного обеспечения, способствует совместной работе и упрощает взаимодействие с пользователем. Некоторые из преимуществ Swagger включают, но не ограничиваются:

  • Синхронизирует документацию API с сервером и клиентом в одном темпе.
  • Позволяет нам создавать документацию REST API и взаимодействовать с REST API. Взаимодействие с REST API с помощью Swagger UI Framework дает четкое представление о том, как API реагирует на параметры.
  • Предоставляет ответы в формате JSON и XML.
  • Имеются реализации для различных технологий.
#JavaScript #NodeJS
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу