使用节点JS&Express构建REST API
#javascript #node #express #restapi

我们可以使用HTTP模块创建Web服务器

const http = require('http');

const server = http.createServer((req, res) => {
    if(req.url === '/'){
        res.write('Hellow world');
        res.end();
    }
    if(req.url === '/api/customers'){
        res.write(JSON.stringify([1,2,3]));
        res.end();
    }
});

server.listen(3000);
console.log('Listening on port 3000...')

在这里,我们有一个回调函数,该函数采用两个参数请求和响应,使用此请求对象,我们可以检查传入请求的URL,我们可以为应用程序定义各种途径。

因此,如果您有要求slash api slash客户的请求,这就是我们将如何回应客户的方式。现在,尽管这种方法肯定有效,但它不是很可维护的,因为当我们为应用程序定义了更多路由时,如果此回调函数中的块中的块,我们需要添加更多。

那是一个框架进入图片框架的时候。框架为我们的应用程序提供了适当的结构,因此我们可以在保持应用程序代码可维护的同时轻松地路由。现在,有各种框架可以在值得注意的基础上构建Web应用程序和Web服务器。最受欢迎的是Express

它也非常快速轻巧且完美地记录下来。

现在创建一个restapi文件夹。让我们进入此文件夹并运行npm init --yes。因此,现在我们有了一个软件包JSON文件。最后,我们可以安装npm i express

使用Express构建Web服务器

创建新文件index.js。 Express模块​​,因此我们使用我们的需求函数将其称为“ Express”模块。

require('express')返回我们称之为表达的函数。

const express = require('express')

我们需要像这样调用此函数,并且您可以看到此函数返回按照惯例的type对象,我们调用此对象应用程序,因此我们将结果存储在constant app

const app = express();

因此,这代表我们的应用程序现在应用程序对象具有许多有用的方法,我们拥有诸如get post put delete
之类的方法

app.get()
app.post()
app.put()
app.delete()

所有这些方法都对应HTTP动词或HTTP方法。

您想将http post请求发布到端点,您将使用app.post()

http获取请求,因此此方法采用两个参数,第一个参数是通行证或URL,因此在这里我要使用斜杠来表示网站的路由。现在,第二个参数是callback function这是当我们对此端点的HTTP GET请求时,将被调用的函数。因此,回调函数应有两个参数请求request, response。因此,这是一个代码块,现在此请求对象具有许多有用的属性,可为我们提供有关传入请求的信息。


当我们获得HTTP的请求时,您将通过Hello World消息回复。因此,这就是我们定义路由的方式,我们指定路径和回调函数,该路由也称为路由处理程序。

现在最终我们需要在给定点上聆听,因此我们调用应用程序,以收听我们给出3000之类的端口号,并且可以选择传递一个函数,当应用程序统计信息在给定端口上侦听时将被调用,以便再次我们再次使用arrow function syntax在控制台上显示一些东西。

app.listen(3000, () => console.log('Listening on port 3000'))

现在返回终端并运行node index.js

Listening port

现在让我们定义另一条路线

app.get('/api/courses', (req, res) => {
    res.send([1,2,3])
})

我要简单地返回一个数字,因此发送的响应并通过了三个数字。

回到终端中,我们必须停止此过程并重新开始。因此,按ctrl + c再一次node index.js

在此实施中,如果块我们定义新路由,我们将没有那些。

express给出我们的应用是骨骼是结构。

Nodemon

到目前为止,您已经注意到,每次我们更改此代码时,您都必须返回终端并停止此过程并重新开始。我将向您展示更好的方式,我们将安装名为 nodemon 的节点软件包。安装命令npm i -g nodemon

而不是使用节点运行我们的应用程序。
返回终端并运行nodemon index.js

using nodemon

环境变量

现在,我们需要在此代码中改进的一件事是该端口的硬编码值,因此我们使用了3000个数字,而这可能在您开发机器上起作用,这不太可能在生产环境中不起作用,因为当部署部署时该应用程序到托管环境中该端口由托管环境动态分配。因此,我们不能依靠3000可用。因此,解决此问题的方法是使用环境变量。

在应用程序之外,我将向您展示如何工作。在此应用程序中,我们需要读取此端口环境变量的值以及使用process object的方式。

我们有一个名为“进程”的全局对象,该对象具有许多属性。

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}`))

在这种情况下,我们环境变量的名称,因此,如果设置了此设置,我们将使用此端口,否则我们将使用3000。现在我们可以将结果存储在称为端口的constant中。

最后,让我们删除此内容,最后我们需要用端口替换,并相应地更改消息。

处理请求

创建一门课程的路线。

app.get('/api/courses/:id', (req, res)=> {
    res.send(req.params.id)
})

可能是课程ID或CourseID,但是ID更短,更常规的是我们拥有路线处理程序功能。

现在,我们有两个终点可以获取所有课程,其他两个课程都可以获得一门课程。

app.get('/api/courses', (req, res) => {
    res.send([1,2,3])
})
// /api/courses/1
app.get('/api/courses/:id', (req, res)=> {
    res.send(req.params.id)
})
app.get('/api/courses/:id', (req, res)=> {
    // res.send(req.params.id)
   const course = courses.find(c => c.id === parseInt(req.params.id))
   if(!course){
       res.status(404).send('The course with the give ID was not found')
   }
   res.send(course)

})

处理帖子请求

到目前为止,我们已经创建了两条路线,可以响应HTTP获取请求,并使用此路线来获取所有课程以及单课。

我们使用HTTP POST请求创建新课程。

app.post('/api/courses', (req, res) => {

})

在此路线处理程序中,我们需要读取应在请求正文中的课程对象使用这些属性创建一个新课程对象,然后将该课程对象添加到我们的课程中。

app.post('/api/courses', (req, res) => {
    const course = {
        id: courses.length + 1,
        name: req.body.name
    }
})

我们需要将应用程序称为app.use(express.json())。添加一块中间件。再次在请求处理管道中使用此中间件。

app.post('/api/courses', (req, res) => {
    const course = {
        id: courses.length + 1,
        name: req.body.name
    }
    courses.push(course)
})

,最终通过惯例,当我们在服务器创建新对象或新资源时将对象发布到服务器时,您应该在响应正文中返回该对象。

app.post('/api/courses', (req, res) => {
    const course = {
        id: courses.length + 1,
        name: req.body.name
    }
    courses.push(course)
    res.send(course)
})

Post request
我们可以看到请求的状态为200,这意味着该请求已成功处理。另请参阅响应的主体。

我们将其发送到服务器,因此这是我们在Postman中测试HTTP服务的方式。

我们假设请求的正文中有一个具有名称属性的对象,如果客户端忘记发送此属性或发送无效的名称。

输入验证

作为安全性最佳实践,您永远都不应该相信客户发送的东西。您应该始终验证输入。

app.post('/api/courses', (req, res) => {
    if(!req.body.name || req.body.name.length < 3){
    }
})

不存在或请求该正文的名称小于3,然后我们要给客户一个错误。

恢复的惯例是用HTTP状态代码或400返回响应,这意味着不良请求。

app.post('/api/courses', (req, res) => {
    if(!req.body.name || req.body.name.length < 3){
        res.status(400).send('Name is required and should be minimum 3 character.')
    }   
    return;
    const course = {
        id: courses.length + 1,
        name: req.body.name
    }
    courses.push(course)
    res.send(course)
})

joi npm i joi
验证 将其存储在称为Joi的常数

const Joi = require('joi')

因此,我们现在有这个Joi类,现在将我们的路线处理程序与Joi首先打包,我们需要定义模式。模式定义了我们的物体的形状。

const schema = {
        name: Joi.string().min(3).required();
    }
    Joi.validate(req.body, schema)

此验证方法返回一个对象,让我们存储在常数result

处理请求

更新课程,让我们添加一个新的路由处理程序应用程序,我们使用PUT方法来更新资源。

app.put('/api/courses/:id', (req, res)=> {
    // look up the course
    // if not existing, return 404
    const course = courses.find(c => c.id === parseInt(req.params.id))
    if(!course){
        res.status(404).send('The course with the give ID was not found')
    }
    // validate the coruse
    // if invalid, return 400 - Bad request
    if(!req.body.name || req.body.name.length < 3){
        res.status(400).send('Name is required and should be minimum 3 character.');
        return;
    } 

    // update course
    // return the update course
   course.name = req.body.name;  
   res.send(course)
})

处理删除请求

它非常简单,与到目前为止所做的事情相似。我们需要在我们的课程阵列中找到本课程的索引。我们可以使用此剪接方法从我们的课程数组中删除和对象。

app.delete('/api/courses/:id', (req, res)=> {
    // look up the course
    // if not existing, return 404
    const course = courses.find(c => c.id === parseInt(req.params.id))
    if(!course){
        res.status(404).send('The course with the given ID was not found')
    }
    // delete course
    const index = courses.indexOf(course)
    console.log(index)
    courses.splice(index, 1)
    // if not delete otherse return the same course
   res.send(course)
})

Delete course

index.js文件

const Joi = require('joi')
const express = require('express');
const app = express();
app.use(express.json())

const courses = [
    {id: 1, name: 'course1'},
    {id: 2, name: 'course2'},
    {id: 3, name: 'course3'},
]

app.get('/', (req, res) => {
    res.send('Hello World!!')
})
app.get('/api/courses', (req, res) => {
    res.send(courses)
})
// /api/courses/1
app.get('/api/courses/:id', (req, res)=> {
    // res.send(req.params.id)
   const course = courses.find(c => c.id === parseInt(req.params.id))
   if(!course){
       res.status(404).send('The course with the given ID was not found')
   }
   res.send(course)

})
//http://localhost:3000/api/courses/2018/1
app.get('/api/courses/:year/:month', (req, res)=> {
    res.send(req.params)
})
// Query params:  http://localhost:3000/api/courses/2018/1?sortBy=name
app.get('/api/posts/:year/:month', (req, res)=> {
    res.send(req.query)
})

app.post('/api/courses', (req, res) => {
    // const schema = {
    //     name: Joi.string().min(3).required()
    // }
    // const result = Joi.validate(req.body, schema);
    // console.log(result);

    if(!req.body.name || req.body.name.length < 3){
        res.status(400).send('Name is required and should be minimum 3 character.');
        return;
    }   

    const course = {
        id: courses.length + 1,
        name: req.body.name
    }
    courses.push(course)
    res.send(course)
})


app.put('/api/courses/:id', (req, res)=> {
    // look up the course
    // if not existing, return 404
    const course = courses.find(c => c.id === parseInt(req.params.id))
    if(!course){
        res.status(404).send('The course with the given ID was not found')
    }
    // validate the coruse
    // if invalid, return 400 - Bad request
    if(!req.body.name || req.body.name.length < 3){
        res.status(400).send('Name is required and should be minimum 3 character.');
        return;
    } 

    // update course
    // return the update course
   course.name = req.body.name;  
   res.send(course)
})

app.delete('/api/courses/:id', (req, res)=> {
    // look up the course
    // if not existing, return 404
    const course = courses.find(c => c.id === parseInt(req.params.id))
    if(!course){
        res.status(404).send('The course with the given ID was not found')
    }

    // delete course
    const index = courses.indexOf(course)
    console.log(index)
    courses.splice(index, 1)
    // if not delete otherse return the same course
   res.send(course)
})


// port
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}...`))