使用egg.js开发后端API接口系统
什么是Egg.js
Egg.js 为企业级框架和应用而生,我们希望由 Egg.js 孕育出更多上层框架,帮助开发团队和开发人员降低开发和维护成本。详细的了解可以参考Egg.js的官网:https://eggjs.org/zh-cn/intro/。
Egg.js 奉行『约定优于配置』,按照一套统一的约定进行应用开发,Egg 有很高的扩展性,可以按照团队的约定定制框架,团队内部采用这种方式可以减少开发人员的学习成本。
可以理解Egg.js是一个Node框架,同时它也是基于Koa框架基础上的框架,我们大概了解一下它的前身和主要特点即可。
它的特点有:
本篇随笔不是细说Egg.js 的详细内容,毕竟官网介绍还是比较清晰的,我们主要说使用它来做一个后端的API接口系统,后端肯定需要对数据库进行各种操作,用一个JS的方式来访问数据库,利用egg-sequelize插件,创建和数据库表进行绑定的模型进行操作,还是比较新鲜的,用了会发现确实很方便。用Egg.js来开发后端系统,相当于用前端的语言、做法,来开发后端系统了(虽然Egg.js 也可以用来做前端)。

2、 使用egg.js开发后端API接口系统所需插件
我们推荐直接使用脚手架,只需几条简单指令,即可快速生成项目(npm >=6.1.0
):
$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i
启动项目:
$ npm run dev
其实我们还需要一些额外的插件来跑起来,我的包依赖文件如下所示。
package.json
{
"name": "example",
"version": "1.0.0",
"description": "## Development",
"dependencies": {
"egg": "^2.10.0",
"egg-cors": "^2.2.3",
"egg-jwt": "^3.1.7",
"egg-mysql": "^3.0.0",
"egg-redis": "^2.4.0",
"egg-scripts": "^2.5.0",
"egg-sequelize": "^4.0.2",
"egg-view-nunjucks": "^2.3.0",
"moment": "^2.29.1",
"mysql2": "^2.2.5",
"node": "^15.10.0"
},
"devDependencies": {
"autod": "^3.0.1",
"autod-egg": "^1.0.0",
"egg-bin": "^4.15.0",
"egg-mock": "^3.19.2",
"eslint": "^4.18.1",
"eslint-config-egg": "^7.0.0",
"factory-girl": "^5.0.2",
"sequelize-cli": "^4.0.0"
},
我们来看看红色部分的内容,其中
egg 是本身的框架需要的插件,这个是整个框架的核心基础;egg-scripts 这是部署eggjs项目的工具;
egg-corss 是跨域处理所需要的,用于设置csrf的配置等;
egg-jwt 是用于对用户身份认证的处理插件;
egg-mysql + Mysql2 是我们做Mysql数据库处理说需要的插件;
egg-redis 是我们用到redis操作,所需要的插件,可选。
egg-sequelize 是我们操作数据库的一个插件,提供很多方便的接口进行处理,可以搭配Mysql或者PostgreSQL、MS SQLServer数据库插件进行处理的
egg-view-nunjucks 是展示视图模板的一个插件。
moment 是一个日期处理插件,可以处理各种日期格式、转换的一个插件库。
egg-project
├── package.json
├── app.js (可选)
├── agent.js (可选)
├── app
| ├── router.js
│ ├── controller
│ | └── home.js
│ ├── service (可选)
│ | └── user.js
│ ├── middleware (可选)
│ | └── response_time.js
│ ├── view (可选)
│ | └── home.tpl
│ └── extend (可选)
│ ├── helper.js (可选)
├── config
| ├── plugin.js
| ├── config.default.js
│ ├── config.prod.js
我们这里大概知道以上文件夹和文件的意思即可。
app/router.js
用于配置 URL 路由规则,具体参见 Router。app/controller/**
用于解析用户的输入,处理后返回相应的结果,具体参见 Controller。app/service/**
用于编写业务逻辑层,可选,建议使用,具体参见 Service。app/middleware/**
用于编写中间件,可选,具体参见 Middleware。
'use strict'; exports.sequelize = {
enable: true,
package: 'egg-sequelize',
};
exports.mysql = {
enable: true,
package: 'egg-mysql',
}; exports.nunjucks = {
enable: true,
package: 'egg-view-nunjucks'
};
exports.redis = {
enable: true,
package: 'egg-redis',
};
exports.jwt = {
enable: true,
package: 'egg-jwt',
}; exports.cors = {
enable: true,
package: 'egg-cors',
};
为了访问Mysql数据库,我们还需要在config/config.default.js文件中配置好对应的关系。
config/config.default.js
'use strict'; module.exports = appInfo => {
const config = exports = {}; // use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_{{keys}}'; config.jwt = {
secret: '123456', //自定义token的加密条件字符串,可按各自的需求填写
}; // Mysql
config.sequelize = {
dialect: 'mysql',
host: 'localhost',
port: 3306,
database: 'myprojectdb',
username: 'root',
password: '123456',
define: {
//freezeTableName默认值为false,会自动在表名后加s
freezeTableName: true,
// timestamps默认值为true,会自动添加create_time和update_time
timestamps: false
}
}; // csrf 安全配置
config.security = {
csrf: {
enable: false,
ignoreJSON: true
},
// 允许访问接口的白名单
domainWhiteList: ['*'] // ['http://localhost:8080']
};
config.cors = {
origin: '*',
allowMethods: 'GET, HEAD, PUT, POST, DELETE, PATCH'
}; //........其他配置............... return config;
};
为了给前端提供Web API接口,我们需要为不同的业务对象提供路由入口,路由定义,统一在app/route.js文件中定义。
app/route.js
module.exports = app => {
const { router, controller, jwt } = app; router.get('/', controller.home.index);
router.get('/news', controller.news.list);
router.post('/login', controller.users.login); //登录并生成Token
router.resources('users', '/users', controller.users);
};
以上我们users 是RESTful 的方式来定义路由, 我们提供了 app.router.resources('routerName', 'pathMatch', controller)
快速在一个路径上生成 CRUD 路由结构。
类似RESTful定义
router.resources('posts', '/api/posts', controller.posts);
我们只需要在 posts.js
里面实现对应的函数就可以了。
我这里的users实现了上面部分的接口,以提供列表展示-L、创建-C、获取-R、更新-U、删除-D等操作。
app\controller\users.js
'use strict'; const Controller = require('egg').Controller; //控制器类入口
//实现路由几个常规函数,包括列表及CRUD的操作
class UserController extends Controller { async index() { //展示列表数据-L
const ctx = this.ctx;
const query = {
limit: ctx.helper.parseInt(ctx.query.limit),
offset: ctx.helper.parseInt(ctx.query.offset),
}; var data = await ctx.service.user.list(query);
var json = ctx.helper.json(data)
ctx.body = json
} async show() { //显示某记录具体的数据-R
const ctx = this.ctx;
ctx.body = await ctx.service.user.find(ctx.helper.parseInt(ctx.params.id));
} async create() { //新增一个记录-C
const ctx = this.ctx;
const user = await ctx.service.user.create(ctx.request.body);
ctx.status = 201;
ctx.body = user;
} async update() { //更新指定的记录-U
const ctx = this.ctx;
const id = ctx.helper.parseInt(ctx.params.id);
const body = ctx.request.body;
ctx.body = await ctx.service.user.update({
id,
updates: body
});
} async destroy() { //删除指定的记录-D
const ctx = this.ctx;
const id = ctx.helper.parseInt(ctx.params.id);
await ctx.service.user.del(id);
ctx.status = 200;
}
} module.exports = UserController;
这里UserController 控制器没有直接访问数据库,而是间接通过service对象进行操作数据库的。service中的user.js代码如下所示。
app\service\user.js
'use strict'; const Service = require('egg').Service; //服务类入口,用于封装具体的数据库访问
class User extends Service { async login(usernameOrEmail, password) {
var user = await this.ctx.model.User.findOne({
where: {
$or: [
{ username: usernameOrEmail },
{ emailaddress: usernameOrEmail }
]
}
}); var success = false;
var error = "";
if(user) {
success = true
} return {
success,
error
}
} async list({ offset = 0, limit = 10 }) {
return this.ctx.model.User.findAndCountAll({
offset,
limit,
order: [[ 'creationtime', 'desc' ], [ 'id', 'desc' ]],
});
} async find(id) {
const user = await this.ctx.model.User.findByPk(id);
if (!user) {
this.ctx.throw(404, 'user not found');
}
return user;
} async create(user) {
return this.ctx.model.User.create(user);
} async update({ id, updates }) {
const user = await this.ctx.model.User.findByPk(id);
if (!user) {
this.ctx.throw(404, 'user not found');
}
return user.update(updates);
} async del(id) {
const user = await this.ctx.model.User.findByPk(id);
if (!user) {
this.ctx.throw(404, 'user not found');
}
return user.destroy();
}
} module.exports = User;
而Service中,访问数据库主要通过 egg-sequelize 插件中提供的 this.ctx.model.User 对象进行操作数据库的
sequelize 是一个广泛使用的 ORM 框架,它支持 MySQL、PostgreSQL、SQLite 和 MSSQL 等多个数据源。
app\model\user.js
'use strict'; module.exports = app => {
const { STRING, INTEGER, DATE } = app.Sequelize; const User = app.model.define('abpusers', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
name: STRING(64),
username: STRING(64),
phonenumber: STRING(64),
creationtime: DATE,
lastmodificationtime: DATE,
}); return User;
};
sequelize 定义了数据库不同的类型,它的类型定义如下所示。
Sequelize.STRING // VARCHAR(255)
Sequelize.STRING(1234) // VARCHAR(1234)
Sequelize.STRING.BINARY // VARCHAR BINARY
Sequelize.TEXT // TEXT
Sequelize.TEXT('tiny') // TINYTEXT
Sequelize.CITEXT // CITEXT PostgreSQL and SQLite only. Sequelize.INTEGER // INTEGER
Sequelize.BIGINT // BIGINT
Sequelize.BIGINT(11) // BIGINT(11) Sequelize.FLOAT // FLOAT
Sequelize.FLOAT(11) // FLOAT(11)
Sequelize.FLOAT(11, 10) // FLOAT(11,10) Sequelize.REAL // REAL PostgreSQL only.
Sequelize.REAL(11) // REAL(11) PostgreSQL only.
Sequelize.REAL(11, 12) // REAL(11,12) PostgreSQL only. Sequelize.DOUBLE // DOUBLE
Sequelize.DOUBLE(11) // DOUBLE(11)
Sequelize.DOUBLE(11, 10) // DOUBLE(11,10) Sequelize.DECIMAL // DECIMAL
Sequelize.DECIMAL(10, 2) // DECIMAL(10,2) Sequelize.DATE // DATETIME for mysql / sqlite, TIMESTAMP WITH TIME ZONE for postgres
Sequelize.DATE(6) // DATETIME(6) for mysql 5.6.4+. Fractional seconds support with up to 6 digits of precision
Sequelize.DATEONLY // DATE without time.
Sequelize.BOOLEAN // TINYINT(1) Sequelize.ENUM('value 1', 'value 2') // An ENUM with allowed values 'value 1' and 'value 2'
Sequelize.ARRAY(Sequelize.TEXT) // Defines an array. PostgreSQL only.
Sequelize.ARRAY(Sequelize.ENUM) // Defines an array of ENUM. PostgreSQL only. Sequelize.JSON // JSON column. PostgreSQL, SQLite and MySQL only.
Sequelize.JSONB // JSONB column. PostgreSQL only. Sequelize.BLOB // BLOB (bytea for PostgreSQL)
Sequelize.BLOB('tiny') // TINYBLOB (bytea for PostgreSQL. Other options are medium and long) Sequelize.UUID // UUID datatype for PostgreSQL and SQLite, CHAR(36) BINARY for MySQL (use defaultValue: Sequelize.UUIDV1 or Sequelize.UUIDV4 to make sequelize generate the ids automatically) Sequelize.CIDR // CIDR datatype for PostgreSQL
Sequelize.INET // INET datatype for PostgreSQL
Sequelize.MACADDR // MACADDR datatype for PostgreSQL Sequelize.RANGE(Sequelize.INTEGER) // Defines int4range range. PostgreSQL only.
Sequelize.RANGE(Sequelize.BIGINT) // Defined int8range range. PostgreSQL only.
Sequelize.RANGE(Sequelize.DATE) // Defines tstzrange range. PostgreSQL only.
Sequelize.RANGE(Sequelize.DATEONLY) // Defines daterange range. PostgreSQL only.
Sequelize.RANGE(Sequelize.DECIMAL) // Defines numrange range. PostgreSQL only. Sequelize.ARRAY(Sequelize.RANGE(Sequelize.DATE)) // Defines array of tstzrange ranges. PostgreSQL only. Sequelize.GEOMETRY // Spatial column. PostgreSQL (with PostGIS) or MySQL only.
Sequelize.GEOMETRY('POINT') // Spatial column with geometry type. PostgreSQL (with PostGIS) or MySQL only.
Sequelize.GEOMETRY('POINT', 4326) // Spatial column with geometry type and SRID. PostgreSQL (with PostGIS) or MySQL only.
关于它的接口,可以参考下文档https://itbilu.com/nodejs/npm/sequelize-docs-v5.html了解下。
另外,我们可以在app\extend\helper.js中定义一些常规的辅助函数,方便在控制器或者service对象中使用。
app\extend\helper.js
'use strict';
const moment = require('moment'); module.exports = {
json(data, code, msg, addition) {
return Object.assign({
result: code ? 'fail' : 'success',
code: code || 0,
message: msg,
data,
}, addition);
},
parseInt(string) {
if (typeof string === 'number') return string;
if (!string) return string;
return parseInt(string) || 0;
}, changeTime(time) {
return moment(time * 1000).format('YYYY-MM-DD HH:mm:ss');
},
relativeTime(time) {
return moment(new Date(time * 1000)).fromNow()
},
最后,我们使用npm run dev跑项目
测试下我们用户列表部分的处理。
其他CRUD接口,可以结合C#代码进行客户端的测试,也可以在一个新建的Vue+Element前端项目中进行axios的调用,获取对应的JSON进行测试。
在使用egg.js开发的时候,总体还是很方便,不过就是有时候一些拼写错误,或者一些配置原因,控制台 提示信息不是很明确,需要自己掌握各种排错的经验才行。
使用egg.js开发后端API接口系统的更多相关文章
- Spring Boot入门(四):开发Web Api接口常用注解总结
本系列博客记录自己学习Spring Boot的历程,如帮助到你,不胜荣幸,如有错误,欢迎指正! 在程序员的日常工作中,Web开发应该是占比很重的一部分,至少我工作以来,开发的系统基本都是Web端访问的 ...
- 后端API接口的错误信息返回规范
前言 最近我司要制定开发规范.在讨论接口返回的时候,后端的同事询问我们前端,错误信息的返回,前端有什么意见? 所以做了一些调研给到后端的同事做参考. 错误信息返回 在使用API时无可避免地会因为各种情 ...
- 如何使用 Python 编写后端 API 接口
如何使用 Python 编写后端 API 接口 get API Python3 # coding:utf-8 import json # ModuleNotFoundError: No module ...
- 基于 Laravel、Vue.js开发的全新社交系统----ThinkSNS+
什么是ThinkSNS+ ThinkSNS(简称TS)始于2008年,一款全平台综合性社交系统,为国内外大中小企业和创业者提供社会化软件研发及技术解决方案,目前最新版本为ThinkSNS+.新的产品名 ...
- 使用RAP2和Mock.JS实现Web API接口的数据模拟和测试
最近一直在思考如何对Web API的其接口数据进行独立开发的问题,随着Web API的越来越广泛应用,很多开发也要求前端后端分离,例如统一的Web API接口后,Winform团队.Web前端团队.微 ...
- 浅谈PHP与手机APP开发即API接口开发
API(Application Programming Interface,应用程序接口)架构,已经成为目前互联网产品开发中常见的软件架构模式,并且诞生很多专门API服务的公司,如:聚合数据(http ...
- Nuxt+Express后端api接口配置与实现方式
Nuxt.js 是一个基于 Vue.js 的轻量级应用框架,可用来创建服务端渲染 (SSR) 应用.本文带你了解在 Nuxt.js 中使用 Express 如何编写实现后端的 api 接口. 创建接口 ...
- 浅谈使用 PHP 进行手机 APP 开发(API 接口开发)
做过 API 的人应该了解,其实开发 API 比开发 WEB 更简洁,但可能逻辑更复杂,因为 API 其实就是数据输出,不用呈现页面,所以也就不存在 MVC(API 只有 M 和 C),那么我们来探讨 ...
- 准备开发开放API接口
准备开发APP开放接口,允许JQUERY直接调用http://blog.csdn.net/wuxiangege/article/details/52238968 SIGN的设计与实现http://bl ...
随机推荐
- C# 之 async / await
直接看一个例子 private async void button1_Click(object sender, EventArgs e) { var t = Task.Run(() => { T ...
- AWS注册到连接
1. 注册AWS账号 https://www.cnblogs.com/cmt/p/13912814.html 2.注册完成之后,选择实例 Ubuntu,下载xxx.pem文件,查看实例得到ip 比如我 ...
- 6.PowerShell DSC核心概念之LCM
什么是LCM? 本地配置管理器 (LCM) 是DSC的引擎. LCM 在每个目标节点上运行,负责分析和执行发送到节点的配置. 它还负责 DSC 的许多方面,包括以下各方面. 确定刷新模式(推送或请求) ...
- oslab oranges 一个操作系统的实现 实验二 认识保护模式
https://github.com/yyu/osfs00 实验目的: 理解x86架构下的段式内存管理 掌握实模式和保护模式下段式寻址的组织方式. 关键数据结构.代码组织方式 掌握实模式与保护模式的切 ...
- docker07-数据存储
Docker 内部以及容器之间管理数据,在容器中管理数据主要有两种方式: 数据卷(Volumes) 挂载主机目录 (Bind mounts) 数据卷 是一个可供一个或多个容器使用的特殊目录,它绕过 U ...
- Flatten Arrays & flat() & flatMap()
Flatten Arrays & flat() & flatMap() https://alligator.io/js/flat-flatmap/ "use strict&q ...
- multi selects & mutually exclusive
multi selects & mutually exclusive 互斥 selects import React, { useState, // useEffect, // useRef, ...
- svg 矩阵转换
svg 矩阵转换 https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix https://develope ...
- Baccarat如何点燃DEFI市场?
目前DeFi是成为了各大生态的"兵家必争之地",与此同时DeFi的高收益也成为吸引散户入局的一个利器.而虽然流动性挖矿板块近期的温度有所下降,但是这其中不乏还是有很多收益颇丰的De ...
- NGK内存爆发式增长,看Baccarat将怎样打造全新的全场景金融生态
从数字货币抵押借贷业务出发,DeFi已经形成了覆盖全场景的全新金融生态. 可以说,除了信贷等少数对现实世界信息存在较多依赖的实体业务,DeFi已经实现了传统金融业务的全面链上迁移.大多数传统金融行业存 ...