Construyendo un servidor de auto-documentación en Node.JS

Condiciones:





  • validación a través de Joi





  • usando TypeScript





  • Servidor expreso





  • SWAGGER en / api-docs





Tarea: SECO





Decisión:

Primero debe decidir qué viene primero: el esquema Joi, Swagger o la interfaz TypeScript. Se ha establecido empíricamente que Joi debe convertirse en primario.





1. Instalación de todos los módulos en Express

npm install --save swagger-ui-express
      
      



Agregue líneas a app.ts (index.ts):





import swaggerUI = require('swagger-ui-express')
import swDocument from './openapi'
...
app.use('/api-docs',swaggerUI.serve,swaggerUI.setup(swDocument))

      
      



2. Cree ./openapi.ts

Este archivo contiene información básica sobre el servidor. Puede crearlo (como todos los esquemas a continuación) usando la utilidad SWAGGER. Es importante elegir el protocolo openapi v3.0.0





:





import {swLoginRoute} from './routes/login'

const swagger = {
  openapi: '3.0.0',
  info: {
    title: 'Express API for Dangle',
    version: '1.0.0',
    description: 'The REST API for Dangle Panel service'
  },
  servers: [
    {
      url: 'http://localhost:3001',
      description: 'Development server'
    }
  ],
  paths: {
    ...swLoginRoute
  },
}

export default swagger
      
      



.





3.

openapi-





./routes/login/index.ts:





import {swGetUserInfo} from './get-user-info'
import {swUpdateInfo} from './update-info'
export const swLoginRoute = {
  "/login": {
    "get": {
      ...swGetUserInfo
    },
    "patch": {
      ...swUpdateInfo
    }
  }
}
      
      



/login, : get patch. get-user-into.ts update-info.ts. .





4.

, Joi-.





.





: , .





update-info.ts, ( ):





import schema, {joiSchema} from './update-info.spec/schema'

export const swUpdateInfo = {
  "summary": "update the user info",
  "tags": [
    "login"
  ],
  "parameters": [
    {
      "name": "key",
      "in": "header",
      "schema": {
        "type": "string"
      },
      "required": true
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          ...schema
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Done"
    },
    "default": {
      "description": "Error message"
    }
  }
}
// ...   

      
      



JSON- Swagger-, . :





"schema": {
  ...schema
}

      
      



.





Joi- :





await joiSchema.validateAsync(req.body)
      
      



4. Joi-

Joi:





npm install --save joi joi-to-swagger
      
      



:





const joi = require('joi')
const j2s = require('joi-to-swagger')

// Joi
export const joiSchema = joi.object().keys({
  mode:    joi.string().required(),
  email:   joi.string().email()
})
// end of Joi

const schema = j2s(joiSchema).swagger
export default schema

      
      



Joi- swagger-.





, SWAGGER- . TypeScript-





5. TypeScript

npm install --save-dev gulp @babel/register @babel/plugin-proposal-class-properties @babel/preset-env @babel/preset-typescript
      
      



Gulp. , . gulpfile.ts :





const gulp = require('gulp')
const through = require('through2')
import { compile } from 'json-schema-to-typescript'
const fs = require('fs')

const endName = "schema.ts"
const routes = `./routes/**/*.spec/*${endName}`

function path(str: string) : string
{
   let base = str
   if(base.lastIndexOf(endName) != -1)
     base = base.substring(0, base.lastIndexOf(endName))
   return base
}

gulp.task('schema', () => {
  return gulp.src(routes)
    .pipe(through.obj((chunk, enc, cb) => {
      const filename = chunk.path
      import(filename).then(schema => { // dynamic import
        console.log('Converting', filename)
        compile(schema.default, `IDTO`)
          .then(ts => {
            //console.log(path(filename).concat('interface.ts'), ts)
            fs.writeFileSync(path(filename).concat('interface.ts'), ts)
          })
        })
      cb(null, chunk)
    }))
})


// watch service
const { watch, series } = require('gulp')
exports.default = function() {
  watch(routes, series('schema'))
}
      
      



El script omite todos los subdirectorios denominados * .spec dentro del directorio del enrutador. Allí busca archivos con los nombres * schema.ts y crea una serie de archivos con los nombres * interface.ts





Conclusión

Por supuesto, estos objetos JSON grandes y complejos con la especificación openAPI dan miedo, pero debe comprender que no se escriben manualmente, sino que los genera la utilidad SWAGGER.





Debido a la inexperiencia, el ajuste inicial del mecanismo puede llevar algún tiempo, ¡pero esto ahorrará cientos de horas que podrían dedicarse a la rutina!








All Articles