任务目标
选择合适的 API 风格,实现从接口或资源(领域)建模,到 API 设计的过程
使用 API 工具,编制 API 描述文件,编译生成服务器、客户端原型
使用 Github 建立一个组织,通过 API 文档,实现 客户端项目 与 RESTful 服务项目同步开发
使用 API 设计工具提供 Mock 服务,两个团队独立测试 API
使用 travis 测试相关模块
资源来源
我的博客。
使用CSDN博客导出工具
前端
模仿rest v3 api风格设计api,有users,acticles, reviews, tags四种资源。
"GetArticleById":"/v3/article/{id}",
"GetArticles":"/v3/articles",
"GetCommentsOfArticle":"/v3/article/{id}/comments",
"CreateComment":"/v3/article/{id}/comment",
"SignIn":"/v3/auth/signin",
"SignUp": "/v3/auth/signup"
使用swagger在线编辑器,可以即时响应,使用yaml语法编写API文档。
swagger: "2.0"
info:
description: "A Simple Blog"
version: "1.0.0"
title: "Swagger Blog"
termsOfService: "http://swagger.io/terms/"
contact:
email: "apiteam@swagger.io"
license:
name: "Apache 2.0"
url: "http://www.apache.org/licenses/LICENSE-2.0.html"
host: "blog.swagger.io"
basePath: "/v3"
tags:
- name: "article"
description: "Everything about users' articles"
- name: "user"
description: "Operations about user"
schemes:
- "https"
paths:
/articles:
get:
tags:
- "article"
summary: "Get articles"
description: "Get the title of the request page of articles"
operationId: "GetArticles"
produces:
- "application/json"
parameters:
- name: "page"
in: "query"
description: "the request page"
required: true
type: "string"
responses:
200:
description: "Successful Operation"
schema:
$ref: "#/definitions/ArticlesResponse"
404:
description: "Not Found"
schema:
type: object
properties:
error:
type: string
example:
- "User Not Exists"
- "Article Not Exists"
/article/{id}:
get:
tags:
- "article"
summary: "Get article by id"
description: "Get an article by it's id"
operationId: "GetArticleById"
produces:
- "application/json"
parameters:
- name: "id"
in: "path"
description: "The only Id of the article for the filter"
required: true
type: "integer"
x-exportParamName: "Id"
responses:
200:
description: "Successful Operation"
schema:
$ref: "#/definitions/Article"
400:
description: "Bad Request"
schema:
type: object
properties:
error:
type: string
example:
- "Wrong ArticleId"
404:
description: "Not Found"
schema:
type: object
properties:
error:
type: string
example:
- "Article Not Exists"
/article/{id}/comments:
get:
tags:
- "article"
summary: "Get all comments of an article"
description: "Get all comments of an article"
operationId: "GetCommentsOfArticle"
produces:
- "application/json"
parameters:
- name: "id"
in: "path"
description: "The only id of the article to return"
required: true
type: "integer"
x-exportParamName: "Id"
responses:
200:
description: "Successful Operation"
schema:
$ref: "#/definitions/Comments"
400:
description: "Bad Request"
schema:
type: object
properties:
error:
type: string
example:
- "Wrong ArticleId"
404:
description: "Not Found"
schema:
type: object
properties:
error:
type: string
example:
- "Article Not Exists"
- "Comment Not Exists"
/auth/signup:
post:
tags:
- "user"
summary: "sign up"
description: "Create a new user with the only username"
operationId: "SignUp"
produces:
- "application/json"
parameters:
- in: "body"
name: "body"
description: "Created user object"
required: true
schema:
$ref: "#/definitions/User"
x-exportParamName: "Body"
responses:
200:
description: "Successful Operation"
400:
description: "Bad Requested"
schema:
type: object
properties:
error:
type: string
example:
- "User Exists"
- "Wrong Username or Password"
- "..."
/auth/signin:
post:
tags:
- "user"
summary: "sign in"
description: "Check user with username and password"
operationId: "SignIn"
produces:
- "application/json"
parameters:
- in: "body"
name: "body"
required: true
schema:
$ref: "#/definitions/User"
responses:
200:
description: "Successful Operation"
schema:
type: object
properties:
token:
type: string
404:
description: "Not Found"
schema:
type: object
properties:
error:
type: string
example: "Wrong Username or Password"
/article/{id}/comment:
post:
tags:
- "user"
summary: "create comment"
description: "user creates a comment for the article"
operationId: "CreateComment"
parameters:
- name: "id"
in: "path"
required: true
type: "integer"
x-exportParamName: "Id"
- in: "body"
name: "body"
required: true
schema:
type: object
properties:
content:
type: string
author:
type: string
responses:
200:
description: "Successful Operation"
schema:
$ref: "#/definitions/Comment"
400:
description: "Bad Request"
schema:
type: object
properties:
error:
type: string
example:
- "Article Not Exists"
- "Wrong ArticleId"
- "There is no content in your article"
- "..."
securityDefinitions:
petstore_auth:
type: "oauth2"
authorizationUrl: "http://petstore.swagger.io/oauth/dialog"
flow: "implicit"
scopes:
write:pets: "modify pets in your account"
read:pets: "read your pets"
api_key:
type: "apiKey"
name: "api_key"
in: "header"
definitions:
User:
type: "object"
required:
- "password"
- "username"
properties:
username:
type: "string"
password:
type: "string"
example:
password: "password"
username: "username"
Tag:
type: "object"
properties:
name:
type: "string"
example:
name: "name"
Article:
type: "object"
required:
- "author"
- "content"
- "id"
- "name"
properties:
id:
type: "integer"
name:
type: "string"
tags:
type: "array"
items:
$ref: "#/definitions/Tag"
date:
type: "string"
content:
type: "string"
example:
date: "date"
author: "author"
name: "name"
id: 0
content: "content"
tags:
- name: "name"
- name: "name"
Comment:
type: "object"
required:
- "articleId"
- "author"
- "content"
- "date"
properties:
date:
type: "string"
content:
type: "string"
author:
type: "string"
articleId:
type: "integer"
example:
date: "date"
author: "author"
articleId: 0
content: "content"
Comments :
properties:
contents:
type: "array"
items:
$ref: '#/definitions/Comment'
ArticleResponse:
properties:
id:
type: "integer"
name:
type: "string"
ArticlesResponse:
properties:
Articles:
type: "array"
items:
$ref: "#/definitions/ArticleResponse"
externalDocs:
description: "Find out more about Swagger"
url: "http://swagger.io"
点击在线编辑器上方的Generate Client,选择html2,会生成一个压缩包,里面包含了根据yaml生成的html页面。
点击上方的Generate Server,选择go-server,生成一个已配置好的代码包。
打开其中的routers.go,已经实现了路由匹配和匹配函数调用。
除此之外,article.go定义好了article结构体,article_api.go定义了匹配函数,这样只需要在包含匹配函数的文件里实现功能即可,比较方便。
在GitHub上有swagger-vue-client的生成swagger-vue
生成vue-api-client.js,按照API服务发送请求,获取response的回调函数。
后端
作业要求使用boltDB,boltdb的目标是为不需要完整数据库服务器(如Postgres或MySQL)的项目提供一个简单,快速,可靠的数据库。
BoltDB设计源于LMDB,具有使用Go语言编写、不需要服务器即可运行、支持数据结构、直接使用API存取数据,没有查询语句等特点
BoltDB是键值存储,这意味着没有像SQL RDBMS中的表,没有行,没有列。键值对存储在Buckets中,它们旨在对相似的对进行分组。因此,为了获得Value,需要知道该Value所在的桶和钥匙。
db, err := bolt.Open("my.db", 0600, nil)
if err != nil {
log.Fatal(err)
}
defer db.Close()
开启数据库。
err = db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("User"))
if b != nil {
v := b.Get([]byte(user.Username))
if ByteSliceEqual(v, []byte(user.Password)) {
return nil
} else {
return errors.New("Wrong Username or Password")
}
} else {
return errors.New("Wrong Username or Password")
}
})
读入数据。
err = db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte("User"))
if err != nil {
return err
}
return b.Put([]byte(user.Username), []byte(user.Password))
})
写入数据。
在请求和响应中使用json表示body,服务端收到请求时需要反序列化成结构体,发送响应时需要序列化成字符串。
comment := &Comment{
Date: time.Now().Format("2006-01-02 15:04:05"),
Content: "",
Author: "",
ArticleId: Id,
}
err = json.NewDecoder(r.Body).Decode(&comment)
...
json, err := json.Marshal(response)
mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。
easy mock可以直接导入swagger的所有接口,还能适配注释。
在travis上登陆仓库
打勾需要测试的仓库。
开发好需要集成的library以及测试用例后,在根目录新建.travis.yml
language: go
go:
- 1.x
- '1.8'
- '1.9'
- 1.10.x
script:
- go test -v ./...
env:
global:
secure: kr5JHNTYsh/jezvk88qP91arb+UD/op/5CyOFY7uNYpJ6ZSsJY5fDKyZHjf0VSFmaYqJFMPl6uCASE9baiepeGvBFcy8aI9CNsbLzj2uBNjqqYPmvYGnBjpzp8yknVJKRTitF/kkWtzZcWImHnpvNGHuzXxp/EIBeJtNwjcCRoP/qfGhlZKbLsYFvlWkmRYb0dr8RM5mlmGXPZi8q7m+soVRO8Zjr4QQccybgmhonxlcUrHr6ro+yjjQefoJXRufqoRX0sGyecGYucC4nUpWl5hkDPkQE+Mekhz+rF657SwNsn8nXOFnnUuwsPXE26ak5xF1roEcFk2CpwGZuT7smJZPtw1inXFdIaW+4qllbyxMJkylvFZa5IcvLT3+/eKaQc8Fg6PoxJH0PF3RdtoQVB31cQiPWNm1SecQ6wC64WA/5qN4T5OoRfpt60BFDAITdS62dQGu5LSepcXMWXhxCdQPeDm5Qce6wjJXURubJMpBm0mPWwCNZhJyRw1G5TTyO25NckXQRlObrjltvwAd+7OEUcsYXqhdPtUTIVy6w3XOwT2eC/hP0Yi7qqUMMlJTHUW7Lb9zsEc4UB5BVwgeZ5Y9bVbknJfpt3ygcXAJeeDYxwV9g16KoS7HMFPzwrqlHbiBytIahqarBd4enwqR5RYQPEyetiIDLaJA4SyQ0cE=
notifications:
email:
recipients:
- gaozhen0516@gmail.com
on_success: always
更改项目文件,push到github,travis会自动运行测试脚本。
终端执行travis encrypt AMAP_KEY="xxxx" --add
,AMAP_KEY是环境变量名称,可以对敏感数据xxxx进行加密。
添加邮箱可以接收测试结果通知。