使用 API DSL 将处理器与 REST API 关联, 提供给外部系统访问。
约定
/data/app
, 实际编写时需替换为应用根目录。http://127.0.0.1:5099
, 实际编写时需自行替换。<>
标识自行替换的内容。 例如: icon-<图标名称>
, 实际编写时应替换为: icon-foo
, icon-bar
...文件系统路由
API 采用文件系统路由。 例如 DSL 文件名称为 product.http.yao
则对应接口路由地址为 http://127.0.0.1:5099/api/procuct/<path>
DSL 文件 | 路由地址 |
---|---|
/data/app/apis/product.http.yao | http://127.0.0.1:5099/api/procuct/<path> |
/data/app/apis/project/task.http.yao | http://127.0.0.1:5099/api/project/task/<path> |
在 apis
目录下, 创建一个 API DSL 文件, 关联 models.product.Paginate
处理器
/data/app/apis/product.http.yao
{"name": "产品","version": "1.0.0","description": "产品接口","guard": "-","paths": [{"path": "/search","method": "GET","process": "models.product.Paginate","in": [":query-param", "$query.page", "$query.pagesize"],"out": { "status": 200, "type": "application/json" }},{"path": "/save","method": "POST","guard": "-","process": "models.product.Save","in": [":payload"],"out": { "status": 200, "type": "application/json" }}]}
接口调试
curl -X POST http://127.0.0.1:5099/api/product/save \-H 'Content-Type: application/json' \-d '{ "name":"沙丘六部曲", "remark":"(美) 弗兰克·赫伯特 "}'
curl 'http://127.0.0.1:5099/api/product/search?where.name.match=沙丘&page=1&pagesize=2'
可以使用 Guard 实现 API 请求鉴权 如不希望使用 Guard, 将 guard
字段设置为 -
, 多个 guard
使用 ,
分割。
Yao 提供 bearer-jwt
和 cross-origin
Guard 用于 API JWT 鉴权和响应跨域请求。
修改 /data/app/apis/product.http.yao
DSL 文件,添加 Guard。
{"name": "产品","version": "1.0.0","description": "产品接口","guard": "bearer-jwt","group": "product","paths": [{"path": "/search","guard": "-","method": "GET","process": "models.product.Paginate","in": [":query-param", "$query.page", "$query.pagesize"],"out": { "status": 200, "type": "application/json" }},{"path": "/save","method": "POST","process": "models.product.Save","in": [":payload"],"out": { "status": 200, "type": "application/json" }}]}
接口调试
# 没有权限curl -X POST http://127.0.0.1:5099/api/product/save \-H 'Content-Type: application/json' \-d '{ "name":"沙丘六部曲", "remark":"(美) 弗兰克·赫伯特 "}'## {"code":403,"message":"No permission"}#
curl 'http://127.0.0.1:5099/api/product/search?where.name.match=沙丘&page=1&pagesize=2'
生成 JWT
yao run utils.jwt.Make 1 '::{"id":1, "name":"Admin"}' '::{"issuer":"yao"}'
curl -X POST http://127.0.0.1:5099/api/product/save \-H 'Content-Type: application/json' \-H 'Authorization: Bearer <JWT>' \-d '{ "name":"沙丘六部曲", "remark":"(美) 弗兰克·赫伯特 "}'
Guard 支持自定义,可以使用脚本自定义 Guard, 可以用于接口权限管理。
编写 Guard 逻辑
在 scirpts
目录下, 新建一个 JS 文件, 实现自定义 Guard
/data/app/scripts/guard.js
/*** 自定义接口鉴权* @param {...any} args*/function User(path, params, query, payload, headers) {log.Trace("[guard.User] path: %v", path);log.Trace("[guard.User] params: %v", params);log.Trace("[guard.User] query: %v", query);log.Trace("[guard.User] payload: %v", payload);log.Trace("[guard.User] headers: %v", headers);query = query || {};if (query.error) {throw new Exception("没有权限", 403);}}
添加自定义 Guard
修改 /data/app/apis/product.http.yao
DSL 文件,添加 Guard。
{"name": "产品","version": "1.0.0","description": "产品接口","guard": "bearer-jwt","group": "product","paths": [{"path": "/search","guard": "-","method": "GET","process": "models.product.Paginate","in": [":query-param", "$query.page", "$query.pagesize"],"out": { "status": 200, "type": "application/json" }},{"path": "/save","guard": "bearer-jwt,scripts.guard.User","method": "POST","process": "models.product.Save","in": [":payload"],"out": { "status": 200, "type": "application/json" }}]}
接口调试
生成 JWT
yao run utils.jwt.Make 1 '::{"id":1, "name":"Admin"}' '::{"issuer":"yao"}'
# 模拟没有权限curl -X POST http://127.0.0.1:5099/api/product/save?error=1 \-H 'Content-Type: application/json' \-H 'Authorization: Bearer <JWT>' \-d '{ "name":"沙丘六部曲", "remark":"(美) 弗兰克·赫伯特 "}'## {"code":403,"message":"没有权限"}#
# 放行curl -X POST http://127.0.0.1:5099/api/product/save \-H 'Content-Type: application/json' \-H 'Authorization: Bearer <JWT>' \-d '{ "name":"沙丘六部曲", "remark":"(美) 弗兰克·赫伯特 "}'
# 查看日志tail -n 100 logs/application.log
如果处理器返回值为 Map 类型, out
可在 out.body 和 out.headers 中引用处理器返回值。
添加文件下载接口
修改 /data/app/apis/product.http.yao
DSL 文件,添加 Guard。
{"name": "产品","version": "1.0.0","description": "产品接口","guard": "bearer-jwt","group": "product","paths": [{"path": "/search","guard": "-","method": "GET","process": "models.product.Paginate","in": [":query-param", "$query.page", "$query.pagesize"],"out": { "status": 200, "type": "application/json" }},{"path": "/save","guard": "bearer-jwt,scripts.guard.User","method": "POST","process": "models.product.Save","in": [":payload"],"out": { "status": 200, "type": "application/json" }},{"path": "/download","guard": "-","method": "GET","process": "fs.system.Download", // 返回值为 {"content":"<文件内容>", "type":"<MIME TYPE>"}"in": ["$query.name"],"out": {"status": 200,"body": "{{content}}", // API Body 返回文件内容"headers": { "Content-Type": "{{type}}" } // 响应 Content-Type 设置为文件 MIME TYPE}}]}
接口调试
添加测试文件
echo '<html><strong>It works!</strong></html>' > /data/app/data/test.html
curl -vv http://127.0.0.1:5099/api/product/download?name=/test.html## > GET http://127.0.0.1:5099/api/product/download?name=/test.html HTTP/1.1# > Host: 127.0.0.1:5099# > User-Agent: curl/7.84.0# > Accept: */*# > Proxy-Connection: Keep-Alive# ># * Mark bundle as not supporting multiuse# < HTTP/1.1 200 OK# < Content-Length: 40# < Connection: keep-alive# < Content-Type: text/html; charset=utf-8# < Date: Wed, 16 Nov 2022 15:01:03 GMT# < Keep-Alive: timeout=4# < Proxy-Connection: keep-alive#
通过设置 out.redirect
将请求重定向到指定 URL
添加文件下载接口
修改 /data/app/apis/product.http.yao
DSL 文件,添加 Guard。
{"name": "产品","version": "1.0.0","description": "产品接口","guard": "bearer-jwt","group": "product","paths": [{"path": "/search","guard": "-","method": "GET","process": "models.product.Paginate","in": [":query-param", "$query.page", "$query.pagesize"],"out": { "status": 200, "type": "application/json" }},{"path": "/save","guard": "bearer-jwt,scripts.guard.User","method": "POST","process": "models.product.Save","in": [":payload"],"out": { "status": 200, "type": "application/json" }},{"path": "/download","guard": "-","method": "GET","process": "fs.system.Download","in": ["$query.name"],"out": {"status": 200,"body": "{{content}}","headers": { "Content-Type": "{{type}}" }}},{"path": "/redirect","guard": "-","method": "GET","process": "utils.app.ping","in": [],"out": {"status": 200,"redirect": { "code": 301, "location": "https://yaoapps.com" } // 重定向到 yaoapps.com}}]}
接口调试
添加测试文件
echo '<html><strong>It works!</strong></html>' > /data/app/data/test.html
curl -vv http://127.0.0.1:5099/api/product/redirect# > GET http://127.0.0.1:5099/api/product/redirect HTTP/1.1# > Host: 127.0.0.1:5099# > User-Agent: curl/7.84.0# > Accept: */*# > Proxy-Connection: Keep-Alive# ># * Mark bundle as not supporting multiuse# < HTTP/1.1 302 Found# < Content-Length: 42# < Connection: keep-alive# < Content-Type: text/html; charset=utf-8# < Date: Wed, 16 Nov 2022 15:10:05 GMT# < Keep-Alive: timeout=4# < Location: https://yaoapps.com# < Proxy-Connection: keep-alive
使用 API DSL 将处理器与 REST API 关联, 提供给外部系统访问。
约定
/data/app
, 实际编写时需替换为应用根目录。http://127.0.0.1:5099
, 实际编写时需自行替换。<>
标识自行替换的内容。 例如: icon-<图标名称>
, 实际编写时应替换为: icon-foo
, icon-bar
...文件系统路由
API 采用文件系统路由。 例如 DSL 文件名称为 product.http.yao
则对应接口路由地址为 http://127.0.0.1:5099/api/procuct/<path>
DSL 文件 | 路由地址 |
---|---|
/data/app/apis/product.http.yao | http://127.0.0.1:5099/api/procuct/<path> |
/data/app/apis/project/task.http.yao | http://127.0.0.1:5099/api/project/task/<path> |
在 apis
目录下, 创建一个 API DSL 文件, 关联 models.product.Paginate
处理器
/data/app/apis/product.http.yao
{"name": "产品","version": "1.0.0","description": "产品接口","guard": "-","paths": [{"path": "/search","method": "GET","process": "models.product.Paginate","in": [":query-param", "$query.page", "$query.pagesize"],"out": { "status": 200, "type": "application/json" }},{"path": "/save","method": "POST","guard": "-","process": "models.product.Save","in": [":payload"],"out": { "status": 200, "type": "application/json" }}]}
接口调试
curl -X POST http://127.0.0.1:5099/api/product/save \-H 'Content-Type: application/json' \-d '{ "name":"沙丘六部曲", "remark":"(美) 弗兰克·赫伯特 "}'
curl 'http://127.0.0.1:5099/api/product/search?where.name.match=沙丘&page=1&pagesize=2'
可以使用 Guard 实现 API 请求鉴权 如不希望使用 Guard, 将 guard
字段设置为 -
, 多个 guard
使用 ,
分割。
Yao 提供 bearer-jwt
和 cross-origin
Guard 用于 API JWT 鉴权和响应跨域请求。
修改 /data/app/apis/product.http.yao
DSL 文件,添加 Guard。
{"name": "产品","version": "1.0.0","description": "产品接口","guard": "bearer-jwt","group": "product","paths": [{"path": "/search","guard": "-","method": "GET","process": "models.product.Paginate","in": [":query-param", "$query.page", "$query.pagesize"],"out": { "status": 200, "type": "application/json" }},{"path": "/save","method": "POST","process": "models.product.Save","in": [":payload"],"out": { "status": 200, "type": "application/json" }}]}
接口调试
# 没有权限curl -X POST http://127.0.0.1:5099/api/product/save \-H 'Content-Type: application/json' \-d '{ "name":"沙丘六部曲", "remark":"(美) 弗兰克·赫伯特 "}'## {"code":403,"message":"No permission"}#
curl 'http://127.0.0.1:5099/api/product/search?where.name.match=沙丘&page=1&pagesize=2'
生成 JWT
yao run utils.jwt.Make 1 '::{"id":1, "name":"Admin"}' '::{"issuer":"yao"}'
curl -X POST http://127.0.0.1:5099/api/product/save \-H 'Content-Type: application/json' \-H 'Authorization: Bearer <JWT>' \-d '{ "name":"沙丘六部曲", "remark":"(美) 弗兰克·赫伯特 "}'
Guard 支持自定义,可以使用脚本自定义 Guard, 可以用于接口权限管理。
编写 Guard 逻辑
在 scirpts
目录下, 新建一个 JS 文件, 实现自定义 Guard
/data/app/scripts/guard.js
/*** 自定义接口鉴权* @param {...any} args*/function User(path, params, query, payload, headers) {log.Trace("[guard.User] path: %v", path);log.Trace("[guard.User] params: %v", params);log.Trace("[guard.User] query: %v", query);log.Trace("[guard.User] payload: %v", payload);log.Trace("[guard.User] headers: %v", headers);query = query || {};if (query.error) {throw new Exception("没有权限", 403);}}
添加自定义 Guard
修改 /data/app/apis/product.http.yao
DSL 文件,添加 Guard。
{"name": "产品","version": "1.0.0","description": "产品接口","guard": "bearer-jwt","group": "product","paths": [{"path": "/search","guard": "-","method": "GET","process": "models.product.Paginate","in": [":query-param", "$query.page", "$query.pagesize"],"out": { "status": 200, "type": "application/json" }},{"path": "/save","guard": "bearer-jwt,scripts.guard.User","method": "POST","process": "models.product.Save","in": [":payload"],"out": { "status": 200, "type": "application/json" }}]}
接口调试
生成 JWT
yao run utils.jwt.Make 1 '::{"id":1, "name":"Admin"}' '::{"issuer":"yao"}'
# 模拟没有权限curl -X POST http://127.0.0.1:5099/api/product/save?error=1 \-H 'Content-Type: application/json' \-H 'Authorization: Bearer <JWT>' \-d '{ "name":"沙丘六部曲", "remark":"(美) 弗兰克·赫伯特 "}'## {"code":403,"message":"没有权限"}#
# 放行curl -X POST http://127.0.0.1:5099/api/product/save \-H 'Content-Type: application/json' \-H 'Authorization: Bearer <JWT>' \-d '{ "name":"沙丘六部曲", "remark":"(美) 弗兰克·赫伯特 "}'
# 查看日志tail -n 100 logs/application.log
如果处理器返回值为 Map 类型, out
可在 out.body 和 out.headers 中引用处理器返回值。
添加文件下载接口
修改 /data/app/apis/product.http.yao
DSL 文件,添加 Guard。
{"name": "产品","version": "1.0.0","description": "产品接口","guard": "bearer-jwt","group": "product","paths": [{"path": "/search","guard": "-","method": "GET","process": "models.product.Paginate","in": [":query-param", "$query.page", "$query.pagesize"],"out": { "status": 200, "type": "application/json" }},{"path": "/save","guard": "bearer-jwt,scripts.guard.User","method": "POST","process": "models.product.Save","in": [":payload"],"out": { "status": 200, "type": "application/json" }},{"path": "/download","guard": "-","method": "GET","process": "fs.system.Download", // 返回值为 {"content":"<文件内容>", "type":"<MIME TYPE>"}"in": ["$query.name"],"out": {"status": 200,"body": "{{content}}", // API Body 返回文件内容"headers": { "Content-Type": "{{type}}" } // 响应 Content-Type 设置为文件 MIME TYPE}}]}
接口调试
添加测试文件
echo '<html><strong>It works!</strong></html>' > /data/app/data/test.html
curl -vv http://127.0.0.1:5099/api/product/download?name=/test.html## > GET http://127.0.0.1:5099/api/product/download?name=/test.html HTTP/1.1# > Host: 127.0.0.1:5099# > User-Agent: curl/7.84.0# > Accept: */*# > Proxy-Connection: Keep-Alive# ># * Mark bundle as not supporting multiuse# < HTTP/1.1 200 OK# < Content-Length: 40# < Connection: keep-alive# < Content-Type: text/html; charset=utf-8# < Date: Wed, 16 Nov 2022 15:01:03 GMT# < Keep-Alive: timeout=4# < Proxy-Connection: keep-alive#
通过设置 out.redirect
将请求重定向到指定 URL
添加文件下载接口
修改 /data/app/apis/product.http.yao
DSL 文件,添加 Guard。
{"name": "产品","version": "1.0.0","description": "产品接口","guard": "bearer-jwt","group": "product","paths": [{"path": "/search","guard": "-","method": "GET","process": "models.product.Paginate","in": [":query-param", "$query.page", "$query.pagesize"],"out": { "status": 200, "type": "application/json" }},{"path": "/save","guard": "bearer-jwt,scripts.guard.User","method": "POST","process": "models.product.Save","in": [":payload"],"out": { "status": 200, "type": "application/json" }},{"path": "/download","guard": "-","method": "GET","process": "fs.system.Download","in": ["$query.name"],"out": {"status": 200,"body": "{{content}}","headers": { "Content-Type": "{{type}}" }}},{"path": "/redirect","guard": "-","method": "GET","process": "utils.app.ping","in": [],"out": {"status": 200,"redirect": { "code": 301, "location": "https://yaoapps.com" } // 重定向到 yaoapps.com}}]}
接口调试
添加测试文件
echo '<html><strong>It works!</strong></html>' > /data/app/data/test.html
curl -vv http://127.0.0.1:5099/api/product/redirect# > GET http://127.0.0.1:5099/api/product/redirect HTTP/1.1# > Host: 127.0.0.1:5099# > User-Agent: curl/7.84.0# > Accept: */*# > Proxy-Connection: Keep-Alive# ># * Mark bundle as not supporting multiuse# < HTTP/1.1 302 Found# < Content-Length: 42# < Connection: keep-alive# < Content-Type: text/html; charset=utf-8# < Date: Wed, 16 Nov 2022 15:10:05 GMT# < Keep-Alive: timeout=4# < Location: https://yaoapps.com# < Proxy-Connection: keep-alive