I’ve been building some small applications with KOA and Express, but never put them on the line. This time, MY idea is to put my student server to good use, without saying much, and get straight to the point.

Technology stack used:

  • nodejs
  • Koa2 (Network Programming Framework)
  • Mongodb (non-relational database)
  • JWT (for authentication)
  • Pm2 (for running startup scripts)

What is a REST? What is a restful API?

Representational State Transfer (REST) is a web software architecture style developed by Dr. Roy Thomas Fielding in his doctoral thesis in 2000

Restful API: restful API

Koa onion model

app.use(async (ctx, next) => {
  console.log(1)
  await next()
  ctx.body = '1'
})

app.use(async (ctx, next) => {
  console.log(2)
  await next()
  console.log(3) 
})

app.use(async (ctx, next) => {
  console.log(4)})// 1 2 4 3 
Copy the code

How to write a KOA middleware

const auth = async (ctx,next) => {
  try {
    const {authorization=' '} = ctx.request.header
    const token = authorization.replace('Bearer '.' ')
    console.log('token',token)
    const user = jsonwebtoken.verify(token, scret)
    ctx.state.user = user
  } catch (error) {
    ctx.throw(401, error.message)
  }
  await next()
}
Copy the code

The directory structure is set up

  1. Start a simple service
const Koa = require('koa')
const app = new Koa()

const port = 3000 || process.env.port
app.listen(port, () => {
  console.log(`App is listen on ${port}`)})Copy the code
  1. Set up route and write automatic route reading middleware
// routing
const fs = require('fs')

module.exports = app= > {
  fs.readdirSync(__dirname).forEach(file= > {
    if (file === 'index.js') {return}
    const router = require(`. /${file}`)
    app.use(router.routes()).use(router.allowedMethods())
  })
}

const routing = require('./routes/index')
routing(app)
Copy the code
  1. Ctx.request. body for post request is undefined
const KoaBodyPareser = require('koa-bodyparser')
app.use(KoaBodyPareser())
Copy the code
  1. Connecting to a Database
const mongoose = require('mongoose')
const connectionStr = require('./config').connectionStr

// Connect to the database
mongoose.connect(connectionStr, {
  useNewUrlParser: true.useUnifiedTopology: true= > {}, ()console.log('Database connection successful')
})
.catch(err= > {
  console.log(err)
})

mongoose.connection.on(error, console.error)
Copy the code
  1. Error handling
const error = require('koa-json-error')
app.use(error({
  postFormat: ({stack, ... rest}) = > process.env.NODE_ENV === 'production'? rest : {stack, ... rest} }))Copy the code
  1. Parameter format verification
app.use(parameter(app))
const parameter = require('koa-parameter')
Copy the code

Add, delete, change and check the user interface

  1. Define the user’s data layer model
const mongoose = require('mongoose')
const {Schema, model} = mongoose

const UserSchema = new Schema({
  name: {
    type: String.required: true
  },
  password: {type: String.required: true.select: false
  },
  __v: {
    type: Number.select: false}})module.exports = model('User', UserSchema)
Copy the code
  1. The user’s routing layer router
const KoaRouter = require('koa-router')
const jwt = require('koa-jwt')

const router = new KoaRouter({prefix: '/users'})
const {find, findById, create, update, del, login, checkOwer} = require('.. /controller/users')
const secret = require('.. /config').secret

const auth = jwt({secret})

// Get all users
router.get('/', find)
// Create a user
router.post('/', create)
// Get a specific user
router.get('/:id', findById)
// Update the user
router.patch('/:id',auth, checkOwer, update)
// Delete the user
router.delete('/:id',auth, checkOwer, del)
/ / login
router.post('/login', login)

module.exports = router
Copy the code
  1. User controller Controller
const jsonwebtoken = require('jsonwebtoken')
const User = require('.. /models/users')
const secret = require('.. /config').secret

class UsersCtl {
  async find(ctx) {
    ctx.body = await User.find()
  }
  async findById(ctx) {
    const user = await User.findById(ctx.params.id)
    if(! user) {ctx.throw(404.'User does not exist')}
    ctx.body = user
  }
  async create(ctx) {
    ctx.status = 200
    ctx.verifyParams({
      name: {type: 'string'.required: true},
      password: {type: 'string'.required: true}})const {name} = ctx.request.body
    const repeatUser = await User.findOne({name})
    if (repeatUser) { ctx.throw(409.'User is occupied')}const user = await User(ctx.request.body).save()
    ctx.body = user
  }
  async update(ctx) {
    ctx.verifyParams({
      name: {type: 'string'.required: false},
      password: {type: 'string'.required: false}})const user = await User.findByIdAndUpdate(ctx.params.id, ctx.request.body)
    if(! user) {ctx.throw(404.'User does not exist')}
    ctx.body = user
  }
  async del(ctx) {
    const user = await User.findByIdAndRemove(ctx.params.id)
    if(! user) {ctx.throw(404.'User does not exist')}
    ctx.body = user
    ctx.status = 204
  }
  async login(ctx) {
    ctx.verifyParams({
      name: {type: 'string'.required: true},
      password: {type: 'string'.required: true}})const user = await User.findOne(ctx.request.body)
    if(! user) {ctx.throw(401.'Incorrect username or password')}
    const {_id, name} = user
    const token = await jsonwebtoken.sign({_id, name}, secret, {expiresIn: '1d'})
    ctx.body = {
      token
    }
  }
  async checkOwer(ctx, next) {
    if(ctx.params.id ! == ctx.state.user._id) { ctx.throw(403.'User does not have permissions')}await next()
  }
}

module.exports = new UsersCtl()
Copy the code

The use of the postman

  1. The new collection

  2. Create a request in the collection

  3. Set token as a global variable in Test in the login interface

let jsonData = pm.response.json()
pm.globals.set("token", jsonData.token);
Copy the code
  1. Authization uses tokens in other interfaces that require validation

This is the realization of the project construction and user interface, a good memory is better than bad writing, hereby sum up, next time will be the practice of uploading several pictures.