【Express应用】API设计,中间件,配置环境变量,格式化代码

2,068 阅读4分钟

Express

基于Node.js平台,快速、开放、极简的 Web 开发框架, Express中文官方文档 image.png

API

应用之间通信的接口 image.png

REST架构

Representational State Transfer,表述性状态传递,是一种设计风格,核心就是将我们所有想要共享的数据合理的划分为各个资源image.png

1.2.3 API Endpoint

通常包括我们的资源名称(name),而不加我们需要对其操作的名称(HTTP方法/verb): image.png

4.以JSON形式发送数据

很像JavaScript对象,不同的是其key必须是String类型,value除了是String外还也可以是JSON对象数组。 image.png

  • JSend举例。把数据包装进另一个对象的方法叫做Enveloping,如下, tours是一个JSON对象数组:
app.get('/api/v1/tours', (req, res) => {
    res.status(200).send({
        status:'success',
        result:tours.length,
        data: {
            tours:tours
        }
    })
});
  • express.json中间件

在PostMan中设置POST的body(JSON格式的),官方文档对.json 的解释:It parses incoming requests with JSON payloads and is based on body-parser

image.png

app.use(express.json())//㊥间件
app.post('/api/v1/tours',(req,res)=>{
    console.log(req.body) 
    res.send('DONE')
})

//输出JavaScript对象
{ name: 'TEST', duration: 100000, maxGroupSize: 25 }
//若没有使用㊥间件,输出
undefined
  • JSON方法

JSON.parse() 方法用来解析JSON字符串,构造由字符串描述的JavaScript值或对象 JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串

5.服务端无状态

应用中的数据会随着时间改变,如用户登录状态,当前页码。stateless表示:所有state都在客户端记录,而不在服务端,服务端当前请求的执行不需要之前请求的信息: image.png

中间件

概念

中间件是可用于处理请求和响应对象的函数。中间件定义的顺序很重要,通过在函数体的末尾,调用作为参数传递的下一个函数next('route'),函数将控制权交给下一个中间件。res.send()结束了req-res cycle 就不会再执行其后定义的中间件。从本质上来说,一个 Express 应用就是在调用各种中间件: image.png

应用级中间件

const app = express();
// 没有挂载路径的中间件,应用的每个请求都会先执行该中间件,next()会让其进入下一个中间件
app.use((req, res, next) => {
  console.log('Time:', Date.now());
  next();
});
// 处理任何指向 /api/v1/tours 的HTTP请求,next()后接着进入下一个中间件
app.use('/api/v1/tours'', (req, res, next) => {
  console.log('Request Type:', req.method);
  next();
}
// 处理指向 /api/v1/tours  的 GET 请求
app.get(' /api/v1/tours ', (req, res, next) => {
  res.send('USER');
});

路由

  1. 路由方法(method, HTTP方法衍生):

These routing methods specify a callback function (sometimes called “handler functions”) called when the application receives a request to the specified route (endpoint) and HTTP method. In other words, the application “listens” for requests that match the specified route(s) and method(s), and when it detects a match, it calls the specified callback function.

// GET method route
app.get('/api/v1/tours',  (req, res) => {
  res.send('GET request to the homepage')
})
  1. 路由路径(path)和路由参数(parameter):
Route path: /api/v1/tours/:id/:userid
Request URL: http://localhost:3000/api/v1/tours/5/6
req.params: { "id": "5", "userid": "6" }
  1. 路由事件处理程序(handlers/controllers) 每个路由都可以设置一个或多个回调函数来处理请求,他们按顺序执行。

  2. app.route(url)

串联相同路径下的路由方法,避免冗余,写法:

app.route('/api/v1/tours')
  .get( (req, res) => {
    res.send('Get a tour')
  })
  .post( (req, res) => {
    res.send('Add a tour')
  })
  .patch( (req, res) => {
    res.send('Update the tour')
  })

路由级中间件

  1. express.Router()

Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”. 路由级中间件

const tourRouter = express.Router();//is middleware and also, a mini application
app.use('/api/v1/tours',tourRouter);//Only run on route /api/v1/tours

使用第三方中间件

morgan,cors...

带参数的中间件

app.param('id',(req, res,next,val) => {
    res.send('Get tour ${val}');
    next();
  })

将静态文件显示在浏览器上

app.use(express.static('静态文件所在文件夹相对路径'))

环境变量

Node.js/ Express app可以在不同环境下运行,重要的两个环境是 开发环境生产环境,通过设置不同的环境变量,可以在不同的环境下使用不同的数据库,代码等。

可以通过命令行设置环境变量:

NODE_ENV=development nodemon server.js

还有一种方法是设置.env文件,通过dotenv包使用:

require('dotenv).config({path: './.../.env'})
const {PORT} = process.env

Prettier & ESLint

npm i eslint prettier eslint-config-prettier eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-node eslint-plugin-prettier eslint-plugin-react eslint-config-airbnb

.eslintrc.json

{
  "extends": ["airbnb", "prettier", "plugin:node/recommended"],
  "plugins": ["prettier"],
  "rules": {
    "prettier/prettier": "error",
    "spaced-comment": "off",
    "no-console": "warn",
    "consistent-return": "off",
    "func-names": "off",
    "object-shorthand": "off",
    "no-process-exit": "off",
    "no-param-reassign": "off",
    "no-return-await": "off",
    "no-underscore-dangle": "off",
    "class-methods-use-this": "off",
    "prefer-destructuring": ["error", { "object": true, "array": false }],
    "no-unused-vars": ["error", { "argsIgnorePattern": "req|res|next|val" }]
  }
}