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
- 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
- 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
- Ctx.request. body for post request is undefined
const KoaBodyPareser = require('koa-bodyparser')
app.use(KoaBodyPareser())
Copy the code
- 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
- 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
- Parameter format verification
app.use(parameter(app))
const parameter = require('koa-parameter')
Copy the code
Add, delete, change and check the user interface
- 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
- 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
- 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
-
The new collection
-
Create a request in the collection
-
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
- 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.