/Spark

支教小程序API

Primary LanguagePython

Spark

支教小程序API

框架

API是以python的flask框架搭建,数据库的访问使用Sqlalchemy的orm库

flask

  • flask是一个web框架,可以快速搭建web服务。有url路由,模版等功能
  • flask教程 https://www.w3cschool.cn/flask/
  • 微信读书《Flask Web开发实战:入门 进阶与原理解析》
  • Spark的API主要用到了@app.route的url路由,快速实现一个简单的http server。

Sqlalchemy

API协议

鉴权和登陆

登陆流程参照小程序登陆 步骤: 1 前台从微信获得code 2 将code请求后端的login接口。login接口返回token 3 后续前台请求后台接口,把token放入http的authorization中进行请求

举例: 1 请求login和返回值

curl -i  https://api.sparkcharity.cn/login?code=0430lqzJ0MDg7a2Nj3AJ0RTqzJ00lqzZ
--------
{"msg": "ok", "code": 0, "data": {"token": "eyJhbGciOiJIUzUxMiIsImV4cCI6MTU4MjE4NjI5NywiaWF0IjoxNTgwOTc2Njk3fQ.eyJvcGVuaWQiOiI1NTE3dGhpc2NvZGUifQ.WjsrCFLd4wry2zBKH1UaNceu_CO2I3LgIYFeWAEEKbUvVrRSHYrLBCL3RAfbm8GOzsp3ZVWoiU45kFpRQbF9dQ"}}

2 authorization中增加token 请求api

curl "https://api.sparkcharity.cn:1443/api" -u eyJhbGciOiJIUzUxMiIsImV4cCI6MTU4MjE4NzUyMiwiaWF0IjoxNTgwOTc3OTIyfQ.eyJvcGVuaWQiOiI1NTE3dGhpc2NvZGUifQ.jWp_W03CruCx5IRicP1npTF8HH0xHAgCswaeJRnf3HPSyfopSYNvmiVg3r5BH8K_PlEuYVnJKcQDFgKScpXaTQ:unused -d'{"action":"student.add","data":{"name":"yangshuai", "phone":"6666"}}'

协议总览

url

https://api.sparkcharity.cn/api

https协议, 请求路径为/api。以POST方式请求,请求和返回为json格式。

请求参数

{
  "action": "student.add",
  "data": {
    "wxOpenId": "123123",
    "name": "yangshuai",
    "phone": "666666"
  }
}

请求参数分为两部分:

  • action:action分为两部分 module.method,第一部分为module,第二部分为module对应的处理函数。
  • data: 传入的参数

响应参数

{
  "msg": "sucess",
  "code": 0,
  "data": {
    "qq": null,
    "school": null,
    "studyAbroad": null,
    "name": "yangshuai",
    "hoby": null,
    "age": null,
    "parentName": null,
    "department": null,
    "id": 3,
    "phone": "666666",
    "birthday": "2019-08-01",
    "socialExpirence": null,
    "advice": "xxxxxx",
    "teachExpirence": null,
    "parentJob": null,
    "applyDate": "2019-09-15 00:00:00",
    "wxOpenId": "123123",
    "gende": "MAN",
    "applySchedule": null,
    "parentPhone": null
  }
}

响应参数分为三部分:

  • code: 返回码。整型,返回0为成功,非0表示错误。 另外http的返回码非200,请求也是错误
  • msg: 返回的错误消息
  • data: 返回的数据

接口列表

接口 说明
user.get 获得用户的角色信息。主要返回用户的wxOpenId和role。role表示了用户的角色,student:学生;volunteer: 志愿者。
volunteer.add 数据库中增加volunteer。name是必须传入。与tVolunteer表对应
volunteer.get 查询volunteer。不需要传入参数,通过token翻译出wxOpenId。与tVolunteer表对应
volunteer.update 更改volunteer的信息。id是必传的,更改指定id的信息。除了id和wxOpenId不可更改外,在data中的传入的字段都可以更改。与tVolunteer表对应
student.add 数据库中增加student。name是必须传入。与tStudent表对应
student.get 查询student。不需要传入参数,通过token翻译出wxOpenId。与tStudent表对应
student.update 更改student的信息。根据id来更新。与tStudent表对应
class.create 创建一个课程。name, startTime, endTime是必须的参数。与tClass表对应
class.get 拉取课程信息。传入的参数比较多,见下面的具体接口描述
class.update 更改课程信息。可以更改老师,课程时间。与tClass表对应。更改老师,可以用这个接口更改
class.getWithStudent 根据class id获取班级报名的同学。详见接口描述
class.delete 根据class id删除课程。
class.studentSelectClass 同学选课。传入的参数为classId, studentIds。studentIds为同学Id的数组。
class.studentUnSelectClass 同学取消选课。传入的参数为classId, studentId。
class.studentSignIn 同学上课签到。传入的参数为classId, studentId。
class.studentGetClass 获得同学已报名的课程。studentId为必须,其他参数见接口详细列表
class.feedback 课程反馈。studentId和classId为必传;其他字段为被修改的字段。

class.create

创建课程 例子

curl  -u token:unused https://localhost/api -d'{"action":"class.create", "data":{"name":"class for englist", "startTime":"2019-12-01 09:00:00", "endTime":"2019-12-01 10:00:00", "volunteerId":2}}'

-----------
{"msg": "sucess", "code": 0, "data": []}

user.get

获得用户的角色信息 入参 data参数为{}, 没有额外参数。会根据token直接找到对应的wxOpenId

出参

字段 类型 说明
wxOpenId string wxOpenId
wxSessionKey string wxSessionKey
role string 用户角色。student:学生; volunteer: 志愿者。

代码逻辑 在调用login的时候,会在tUser中插入新的记录,记录wxOpenId和wxSessionKey, 而role是空的。只有在调用student.add或volunteer.add的时候,会修改role为相应的值。

举例:

curl "https://api.sparkcharity.cn:443/api" -u eyJhbGciOiJIUzUxMiIsImV4cCI6MTU4MjE4NzUyMiwiaWF0IjoxNTgwOTc3OTIyfQ.eyJvcGVuaWQiOiI1NTE3dGhpc2NvZGUifQ.jWp_W03CruCx5IRicP1npTF8HH0xHAgCswaeJRnf3HPSyfopSYNvmiVg3r5BH8K_PlEuYVnJKcQDFgKScpXaTQ:unused -d'{"action":"user.get","data":{}}'

----

{"msg": "sucess", "code": 0, "data": {"role": "student", "wxOpenId": "5517thiscode", "wxSessionKey": "5517thiscode", "createTime": "2020-02-06 16:44:34"}}

class.get

根据条件拉取课程信息。 入参

字段 类型 必须 说明
id int 课程id
begin string 时间过滤开始时间,格式2019-10-01 10:00:00
end string 时间过滤结束时间,格式2019-10-01 10:00:00
volunteerId int 老师的Id
name string 课程名称
offset int 分页查找的offset
limit int 分页查找的limit

出参 data是数组,数组中每个字段为

字段 类型 说明
id int 课程id
name string 课程名称
startTime string 课程开始时间
endTime string 课程结束时间
volunteerId int 老师的Id
volunteerOpenId string 老师的openId
volunteerName string 老师的名称

例子

curl  -k -i https://localhost/api -d'{"action":"class.get", "data":{"limit":2, "offset":0, "begin":"2019-12-01 10:00:00"}}'

-------------
{"msg": "ok", "code": 0, "data": [{"volunteerOpenId": "123123", "name": "ownyang", "volunteerId": 2, "volunteerName": "yangshuai", "startTime": "2019-12-10 10:00:00", "endTime": "2019-12-10 12:00:00", "id": 1}]}

class.getWithStudent

拉取具体某个课程的同学 入参

字段 类型 必须 说明
id int 课程的id

出参数 返回的class信息,包含了class.get中的信息。另外增加了students字段,这是个数组,数组元素为学生信息。

字段 类型 说明
studentId int 学生的Id
studengOpenId stirng 学生的openId
studentName string 学生的名称

例子

curl  -k -i https://localhost/api -d'{"action":"class.getWithStudent", "data":{"id":1}}'

-----------------
{"msg": "ok", "code": 0, "data": {"volunteerOpenId": "123123", "name": "ownyang", "students": [{"studentId": 1, "studentOpenId": "123123", "studentName": "yangshuai"}, {"studentId": 2, "studentOpenId": "", "studentName": ""}, {"studentId": 3, "studentOpenId": "", "studentName": ""}], "volunteerId": 2, "volunteerName": "yangshuai", "startTime": "2019-12-10 10:00:00", "endTime": "2019-12-10 12:00:00", "id": 1}}

class.studentGetClass

拉取具体某个同学的所选的课程 入参

字段 类型 必须 说明
studentId int 学生的id
begin string 时间过滤开始时间,格式2019-10-01 10:00:00
end string 时间过滤结束时间,格式2019-10-01 10:00:00
offset int 分页查找的offset
limit int 分页查找的limit
classId int 班级ID。可选参数

出参数 data是数组,数组元素为课程信息,字段为

字段 类型 说明
classId int 课程id
className string 课程名称
startTime string 课程开始时间
endTime string 课程结束时间
volunteerId int 老师的Id
volunteerName string 老师的名称
studentId int 学生的Id
studentName string 学生的名称
state int 是否签到。0:未签到; 1:签到

例子

curl  -k -i https://localhost/api -d'{"action":"class.studentGetClass", "data":{"studentId":1}}'

-----------------
{"msg": "ok", "code": 0, "data": [{"classId": 1, "studentId": 1, "volunteerId": 2, "className": "ownyang", "state": 0, "studentName": "yangshuai", "volunteerName": "yangshuai", "startTime": "2019-12-10 10:00:00", "endTime": "2019-12-10 12:00:00"}]}

代码结构

  • app.py flask的http请求入口处理。将/api的请求,路由到apiDispatch函数处理。根据action找到handler/中的处理module
  • handler/volunteer.py 处理action=volunteer.xxxx 的消息。
  • handler/student.py 处理action=student.xxxx 的消息。
  • handler/class.py 课程相关的接口
  • model/Volunteer.py Volunteer的model类,对应数据库中tVolunteer表。是Sqlalchemy的orm对应的类。 handler/volunteer.py会import这个文件,操作数据库.
  • model/Student.py Student的model类,对应数据库中Student表。是Sqlalchemy的orm对应的类。 handler/student.py会import这个文件,操作数据库.
  • model/Class.py Class的model类,对应数据库中Class表。是Sqlalchemy的orm对应的类。 handler/class.py会import这个文件,操作数据库.
  • model/ClassStudent.py ClassStudent的model类,对应数据库中ClassStuent表, 学生课程关系表。是Sqlalchemy的orm对应的类。 handler/class.py会import这个文件,操作数据库.
  • restart.sh 简单重启webserver的脚本

数据库表设计

根据设计文档,创建了tVolunteer和tStudent两张表

CREATE TABLE IF NOT EXISTS `tVolunteer` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `wxOpenId` varchar(128) NOT NULL,
  `name` varchar(128) NOT NULL,
  `gende` enum('MAN','WOMEN') DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `school` varchar(128) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `qq` varchar(32) DEFAULT NULL,
  `parentName` varchar(128) DEFAULT NULL,
  `parentPhone` varchar(20) DEFAULT NULL,
  `parentJob` varchar(128) DEFAULT NULL,
  `studyAbroad` varchar(128) DEFAULT NULL,
  `teachExpirence` text,
  `advice` text,
  `hoby` varchar(128) DEFAULT NULL,
  `socialExpirence` text,
  `department` varchar(128) DEFAULT NULL,
  `applyDate` datetime DEFAULT NULL,
  `applySchedule` enum('DOING','DONE','REJECT') DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `tStudent` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `wxOpenId` varchar(128) NOT NULL,
  `name` varchar(128) NOT NULL,
  `gende` enum('MAN','WOMEN') DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `school` varchar(128) DEFAULT NULL,
  `grade` varchar(128) DEFAULT NULL,
  `qq` varchar(32) DEFAULT NULL,
  `parentName` varchar(128) DEFAULT NULL,
  `parentPhone` varchar(20) DEFAULT NULL,
  `parentJob` varchar(128) DEFAULT NULL,
  `applyDate` datetime DEFAULT NULL,
  `applySchedule` enum('DOING','DONE','REJECT') DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `tClass` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  `volunteerId` int(11)  default 0,
  `startTime` datetime NOT NULL,
  `endTime` datetime NOT NULL,
  `createTime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `rClassStudent` (
  `classId` int(11) NOT NULL,
  `studentId` int(11) NOT NULL,
  `state` int(11) default 0,
  PRIMARY KEY (`classId`,`studentId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `tUser` (
  `wxOpenId` varchar(128) NOT NULL,
  `wxSessionKey` varchar(128) NOT NULL,
  `role` varchar(32) default NULL,
  `createTime` timestamp  DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`wxOpenId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1


数据库简要说明下

说明
tVolunteer 老师的表。wxOpenId 是唯一的。主键是自增的id,本系统建议使用id来传参数。
tStudent 学生的表。wxOpenId 是唯一的。主键是自增的id,本系统建议使用id来传参数。
tClass 课程表。主键id是自增的,其中volunteerId是老师的id,一个课程对应一个老师。
rClassStudent 课程和学生的关系表。主要是classId和studentId.