Việc xây dựng RESTful API trên NodeJs sử dụng Express chắc nhiều dev đều đã biết và xây dựng dễ dàng. Nhưng sau khi xây dựng API theo cách này thì Dev lại phải mất công tự tạo một tài liệu API trên một trình soạn thảo nào đó để gửi cho bên thứ ba cần tích hợp API, và tài liệu API này cũng không có giao diện để đối tác có thể kiểm tra được API. Và Swagger sẽ giúp bạn làm điều này một cách rất đơn giản. Swagger là một công cụ tuyệt vời vì nó giúp chúng ta tạo tài liệu rõ ràng và gọn gàng, cung cấp một trang trực quan tuyệt vời cho những người dùng có thể tự kiểm tra chức năng API một cách dễ dàng và nhanh chóng.
Mục lục
RESTful API là gì?
RESTful API là một tiêu chuẩn dùng trong việc thiết kế các API cho các ứng dụng web để quản lý các tài nguyên. RESTful là một trong những kiểu thiết kế API được sử dụng phổ biến ngày nay để cho các ứng dụng (web, mobile…) khác nhau giao tiếp với nhau.
Chức năng quan trọng nhất của REST là quy định cách sử dụng các HTTP method (như GET, POST, PUT, DELETE…) và cách định dạng các URL cho ứng dụng web để quản các resource. RESTful không quy định logic code ứng dụng và không giới hạn bởi ngôn ngữ lập trình ứng dụng, bất kỳ ngôn ngữ hoặc framework nào cũng có thể sử dụng để thiết kế một RESTful API.
API Document là gì? Tại sao cần có tài liệu API Document?
API Document (Tài liệu API) là sổ tay kỹ thuật, chứa thông tin về cách sử dụng API và cách sử dụng nó. Tài liệu cũng mô tả loại định dạng dữ liệu mà API mong đợi trong yêu cầu và loại nào được trả về từ nó.
Như với mọi công nghệ, phải có một hướng dẫn để giúp người khác hiểu cách sử dụng nó. Tài liệu API giúp mọi người hiểu loại hoạt động nào có thể được thực hiện và tài nguyên nào chúng có thể được chấp nhận và truy xuất. Swagger sẽ giúp chúng ta làm cho API của chúng tôi dễ dàng sẵn sàng và kiểm tra một số chức năng.
Hôm nay chúng ta sẽ tập trung vào việc tạo một API RESTful đơn giản và tích hợp Swagger với đặc tả Open API 3.0. Tài liệu có thể truy cập thông qua trình duyệt với UI dễ nhìn và có thể kiểm tra trực tiếp các API trên giao diện (Xem ảnh dưới).
Tài liệu API nãy sẽ bao gồm những gì?
- Tài liệu cho GET, POST, PUT, DELETE
- Mô tả tài nguyên
- Điểm cuối và phương pháp
- Sơ đồ Yêu cầu/Phản hồi
- Kiểu dữ liệu và tham số được chấp nhận
- ví dụ
Tài liệu API sẽ bao gồm những gì?
- Mô tải API
- Endpoints và Methods
- Schema của Request/Response
- Kiểu dữ liệu và các tham số được chấp nhận
- Các ví dụ
Xây dựng API và API Document với Swagger
Trong ví dụ này, chúng ta sẽ sử dụng NodeJs, Express và Swagger. Đầu tiên chúng ta tạo project NodeJs và cài đặt một số thư viện cần thiết bằng lệnh sau:
npm init
npm install express swagger-jsdoc swagger-ui-express
Trong tệp package.json chúng ta thêm dòng dưới để kích hoạt các mô đun ES6.
"type":"module"
Project của chúng ta sẽ có cấu trúc thư mục như sau:
├── controllers
│ └── hero.controller.js
├── index.js
├── package.json
├── routes
│ ├── hero.routes.js
│ └── index.js
└── swagger.js
Trong tệp index.js, chúng ta sẽ tạo ứng dụng Express cơ bản và cấu hình cho Swagger:
import express from 'express'
import router from './routes/index.js'
import swaggerDocs from './swagger.js'
const app = express()
const port = 5000
app.use(express.json())
app.use(router)
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
swaggerDocs(app, port)
})
Tiếp theo chúng ta tạo tệp swagger.js để cấu hình route và document cho Swagger:
import swaggerJsdoc from 'swagger-jsdoc'
import swaggerUi from 'swagger-ui-express'
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'Hero API',
description: 'Example of CRUD API ',
version: '1.0.0',
},
},
// looks for configuration in specified directories
apis: ['./routes/*.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
Bây giờ, chúng ta thiết lập các API route cùng với đặc tả OpenAPI được trình bày theo định dạng YAML trong tệp routes/index.js. Tất cả các trường trong đặc tả đều phân biệt chữ hoa chữ thường. Để có khả năng truy cập và dễ đọc hơn, chúng tôi sẽ đặt các thông số kỹ thuật ngay phía trên các API route.
import express from 'express'
import heroRoutes from './hero.routes.js'
const router = express.Router()
/**
* @openapi
* /ping:
* get:
* tags:
* - Ping
* description: Returns API operational status
* responses:
* 200:
* description: API is running
*/
router.get('/ping', (req, res) => res.sendStatus(200))
router.use(heroRoutes)
export default router
Hero API sẽ bao gồm 4 yêu cầu: GET, POST, PUT, DELETE. Đối với mỗi yêu cầu, chúng ta sẽ viết thông số kỹ thuật cho phép người dùng API biết loại đầu vào mà API của chúng tôi mong đợi và những gì nó trả về cùng với mã phản hồi. Chúng ta sẽ giữ riêng logic của nó trong thư mục controllers. Toàn bộ thông tin này khai báo trong tệp routes/hero.routes.js:
import express from 'express'
import {
getHeroesHandler,
addHeroHandler,
deleteHeroHandler,
editHeroHandler,
} from '../controllers/hero.controller.js'
const router = express.Router()
/**
* @openapi
* '/api/heroes':
* get:
* tags:
* - Hero
* summary: Get all heroes
* responses:
* 200:
* description: Success
* content:
* application/json:
* schema:
* type: array
* items:
* type: object
* properties:
* id:
* type: number
* name:
* type: string
* 400:
* description: Bad request
*/
router.get('/api/heroes', getHeroesHandler)
/**
* @openapi
* '/api/hero':
* post:
* tags:
* - Hero
* summary: Create a hero
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - id
* - name
* properties:
* id:
* type: number
* default: 2
* name:
* type: string
* default: New Hero Name
* responses:
* 201:
* description: Created
* 409:
* description: Conflict
* 404:
* description: Not Found
*/
router.post('/api/hero', addHeroHandler)
/**
* @openapi
* '/api/hero':
* put:
* tags:
* - Hero
* summary: Modify a hero
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - id
* - name
* properties:
* id:
* type: number
* default: 1
* name:
* type: string
* default: Hulk
* responses:
* 200:
* description: Modified
* 400:
* description: Bad Request
* 404:
* description: Not Found
*/
router.put('/api/hero', editHeroHandler)
/**
* @openapi
* '/api/hero/{id}':
* delete:
* tags:
* - Hero
* summary: Remove hero by id
* parameters:
* - name: id
* in: path
* description: The unique id of the hero
* required: true
* responses:
* 200:
* description: Removed
* 400:
* description: Bad request
* 404:
* description: Not Found
*/
router.delete('/api/hero/:id', deleteHeroHandler)
export default router
Tiếp theo, chúng ta sẽ tạo tệp controllers/hero.controller.js có chứa các chức năng chịu trách nhiệm xử lý các yêu cầu đến và trả về dữ liệu thích hợp.
let heroes = [
{
id: 1,
name: 'Batman',
},
{ id: 2, name: 'Spiderman' },
]
export async function getHeroesHandler(req, res) {
res.status(200).json(heroes)
}
export async function addHeroHandler(req, res) {
if (heroes.find((hero) => hero.id === req.body.id)) {
res.status(409).json('Hero id must be unique')
}
else{
heroes.push(req.body)
res.status(200).json(heroes)
}
}
export async function deleteHeroHandler(req, res) {
const index = heroes.findIndex((hero) => hero.id == req.params.id)
if (index >= 0) {
heroes.splice(index, 1)
res.status(200).json(heroes)
} else res.status(400).send()
}
export async function editHeroHandler(req, res) {
const index = heroes.findIndex((hero) => hero.id == req.body.id)
if (index >= 0) {
heroes.splice(index, 1, req.body)
res.status(200).json(heroes)
} else res.status(400).send()
}
Giờ đây, chúng ta có thể bắt đầu API của mình bằng lệnh sau:
node index.js
Trên trình duyệt bạn mở link http://localhost:5000/docs để xem tài liệu API đồng thời có tự kiểm tra các API một cách nhanh chóng và dễ dàng.
Trả lời