一. 作业内容
模仿 Github,设计一个博客网站的 API
二. 博客API设计
1. 针对个人博客时:
1) 获取自己博客下的所有文章
GET /api/v1/user/articles
查看文章时,使用GET方法。这里用单数user指代自己一个人且不用指定自己用户名或者id。v1代表版本号。
响应内容
HTTP/1.1 200 OK
{
"count":100,
"items":[
{
"id" : "01234567-89ab-cdef-0123-456789abcdef",
"name" : "example",
"created_time": 1496676420000,
"updated_time": 1496676420000,
...
},
...
]
}
失败响应
HTTP/1.1 403 UC/AUTH_DENIED
Content-Type: application/json
{
"code": "INVALID_ARGUMENT",
"message": "{error message}",
"cause": "{cause message}",
"request_id": "01234567-89ab-cdef-0123-456789abcdef",
"host_id": "{server identity}",
"server_time": "2019-11-22T22:07:00Z"
}
2) 根据文章id获取自己的文章
GET /api/v1/user/articles/:id
这里把文章名,即:(article)id看作是层级数据。
响应内容
HTTP/1.1 200 OK
{
"count":100,
"items":[
{
"id" : "01234567-89ab-cdef-0123-456789abcdef",
"name" : "example",
"created_time": 1496676420000,
"updated_time": 1496676420000,
...
},
...
]
}
失败响应
HTTP/1.1 403 UC/AUTH_DENIED
Content-Type: application/json
{
"code": "INVALID_ARGUMENT",
"message": "{error message}",
"cause": "{cause message}",
"request_id": "01234567-89ab-cdef-0123-456789abcdef",
"host_id": "{server identity}",
"server_time": "2019-11-22T22:07:00Z"
}
3) 获取自己某主题分类下的所有文章
GET /api/v1/user/articles/topics
其中,topics表示主题类型。
响应内容
HTTP/1.1 200 OK
{
"count":100,
"items":[
{
"id" : "01234567-89ab-cdef-0123-456789abcdef",
"name" : "example",
"created_time": 1496676420000,
"updated_time": 1496676420000,
...
},
...
]
}
失败响应
HTTP/1.1 403 UC/AUTH_DENIED
Content-Type: application/json
{
"code": "INVALID_ARGUMENT",
"message": "{error message}",
"cause": "{cause message}",
"request_id": "01234567-89ab-cdef-0123-456789abcdef",
"host_id": "{server identity}",
"server_time": "2019-11-22T22:07:00Z"
}
4) 创建文章
POST api/v1/user/articles
创建新的文章时,采用POST方法。用单数user指代自己一个人,不用指定自己用户名或者id。其中user是主资源,article是子资源。
响应内容
HTTP/1.1 201 CREATED
{
"count":100,
"items":[
{
"id" : "01234567-89ab-cdef-0123-456789abcdef",
"name" : "example",
"created_time": 1496676420000,
...
},
...
]
}
失败响应
HTTP/1.1 400 UC/AUTH_DENIED
Content-Type: application/json
{
"code": "INVALID_ARGUMENT",
"message": "{error message}",
"cause": "{cause message}",
"request_id": "01234567-89ab-cdef-0123-456789abcdef",
"host_id": "{server identity}",
"server_time": "2019-11-22T22:07:00Z"
}
5) 修改文章
PUT api/v1/user/articles/:id
修改一篇文章时,采用PUT方法。因为只能用户自己修改,所以只需要层次数据:id来指明要修改的文章。用单数user指代自己一个人,不用指定自己用户名或者id。
响应内容
HTTP/1.1 200 OK
{
"count":100,
"items":[
{
"id" : "01234567-89ab-cdef-0123-456789abcdef",
"name" : "example",
"created_time": 1496676420000,
"updated_time": 1496676420000,
...
},
...
]
}
失败响应
HTTP/1.1 409 UC/AUTH_DENIED
Content-Type: application/json
{
"code": "INVALID_ARGUMENT",
"message": "{error message}",
"cause": "{cause message}",
"request_id": "01234567-89ab-cdef-0123-456789abcdef",
"host_id": "{server identity}",
"server_time": "2019-11-22T22:07:00Z"
}
6) 删除文章
DELETE api/v1/user/articles/:id
删除一篇文章时,采用DELETE方法。和修改时一样,因为只能用户自己删除文章,所以只需要层次数据:id来指明要修改的文章。用单数user指代自己一个人,不用指定自己用户名或者id。
响应内容
HTTP/1.1 204 NOT CONTENT
{
"count":100,
"items":[
{
},
...
]
}
失败响应
HTTP/1.1 404 UC/AUTH_DENIED
Content-Type: application/json
{
"code": "NOT_FOUND",
"message": "{error message}",
"cause": "{cause message}",
"request_id": "01234567-89ab-cdef-0123-456789abcdef",
"host_id": "{server identity}",
"server_time": "2019-11-22T22:07:00Z"
}
2. 针对所有用户博客时:
1) 获取指定用户的所有文章
GET api/v1/users/:username/articles
响应内容
HTTP/1.1 200 OK
{
"count":100,
"items":[
{
"id" : "01234567-89ab-cdef-0123-456789abcdef",
"name" : "example",
"created_time": 1496676420000,
"updated_time": 1496676420000,
...
},
...
]
}
失败响应
HTTP/1.1 403 UC/AUTH_DENIED
Content-Type: application/json
{
"code": "INVALID_ARGUMENT",
"message": "{error message}",
"cause": "{cause message}",
"request_id": "01234567-89ab-cdef-0123-456789abcdef",
"host_id": "{server identity}",
"server_time": "2019-11-22T22:07:00Z"
}
查看文章时,使用GET方法。这一条对比上面几条,user改为了users,指代所有用户。:username是层次数据,指特定用户,是唯一的。articles指该用户的所有文章。
2) 根据用户以及文章id获取具体文章
GET api/v1/users/:username/articles/:id
:username和:id是层次数据,其中,:username指特定用户,是唯一的。articles指该用户的所有文章。:id指文章中的某一特定文章编号,也是唯一的。
响应内容
HTTP/1.1 200 OK
{
"count":100,
"items":[
{
"id" : "01234567-89ab-cdef-0123-456789abcdef",
"name" : "example",
"created_time": 1496676420000,
"updated_time": 1496676420000,
...
},
...
]
}
失败响应
HTTP/1.1 403 UC/AUTH_DENIED
Content-Type: application/json
{
"code": "INVALID_ARGUMENT",
"message": "{error message}",
"cause": "{cause message}",
"request_id": "01234567-89ab-cdef-0123-456789abcdef",
"host_id": "{server identity}",
"server_time": "2019-11-22T22:07:00Z"
}
3) 根据用户和主题获取某用户某主题分类下的所有文章
GET api/v1/users/:username/articles/topics
这里和上面一条不同之处在于不是要获得该用户博客下的某一特定文章,而是要获得该用户博客下的某一特定主题文章,所以用topics而不用:id。
响应内容
HTTP/1.1 200 OK
{
"count":100,
"items":[
{
"id" : "01234567-89ab-cdef-0123-456789abcdef",
"name" : "example",
"created_time": 1496676420000,
"updated_time": 1496676420000,
...
},
...
]
}
失败响应
HTTP/1.1 403 UC/AUTH_DENIED
Content-Type: application/json
{
"code": "INVALID_ARGUMENT",
"message": "{error message}",
"cause": "{cause message}",
"request_id": "01234567-89ab-cdef-0123-456789abcdef",
"host_id": "{server identity}",
"server_time": "2019-11-22T22:07:00Z"
}
3. 用户验证:
1) 验证方式
curl -u "username" https://api.blog.com
其中的https://api.blog.com表示博客网址。
2) 登录失败返回的错误信息
使用无效的凭据进行身份验证将返回401 Unauthorized:
curl -i https://api.blog.com -u foo:bar
HTTP/1.1 401 Unauthorized
{
"message": "Bad credentials",
"documentation_url": "https://developer.blog.com/v3"
}
在短时间内检测到多个具有无效凭据的请求后,API会临时拒绝该用户的所有身份验证尝试(包括具有有效凭据的请求)403 Forbidden:
curl -i https://api.blog.com -u valid_username:valid_password
HTTP/1.1 403 Forbidden
{
"message": "Maximum number of login attempts exceeded. Please try again later.",
"documentation_url": "https://developer.blog.com/v3"
}
3) 用户修改密码
PUT api/v1/users/:username/password/actions/modify
因为“密码修改”这个接口的命名很难完全使用名词来构建路径,所以引入了action命名。
响应内容
HTTP/1.1 200 OK
{
"count":100,
"items":[
{
"id" : "01234567-89ab-cdef-0123-456789abcdef",
"name" : "example",
"password": 1496676420000,
...
},
...
]
}
失败响应
HTTP/1.1 409 UC/AUTH_DENIED
Content-Type: application/json
{
"code": "INVALID_ARGUMENT",
"message": "{error message}",
"cause": "{cause message}",
"request_id": "01234567-89ab-cdef-0123-456789abcdef",
"host_id": "{server identity}",
"server_time": "2019-11-22T22:07:00Z"
}