我们在上一章《快速开始》中了解到了开发API必备的proto.ts的作用,在这一章我们需要实现具体的API啦,我们首先建立一个list文件夹到api下,然后在list文件夹下我们需要新建4个API,分别是增删改查。你可能会觉得:“什么?好麻烦啊,我不想手动建立那么多proto和index.ts”,在这里我们可以在dev环境下,去写便捷操作符,cli会检测到操作符并且自动给你生成模板,比如这样:
Add
接着我们实现一下add接口,我们需要add接口为post请求,并且规定参数必须传递title(string),返回必须是success(boolean)
export interface ReqParams {
title: string;
}
export interface ReqQuery {
}
export interface Res {
success: boolean;
}
import { useApi, Post } from "@swordjs/sword-framework";
import { ReqQuery, ReqParams, Res } from "./proto";
export const main = useApi<{
query: ReqQuery;
params: ReqParams;
res: Res;
}>({
instruct: [Post()],
handler: (ctx) => {
return {
success: true,
};
},
});
Update
我们可以在handler去处理我们的add逻辑,比方说调用数据库的save方法等等…,接着我们同样实现一下update接口,update允许我们传递一个新的title和列表的id:
export interface ReqParams {
title: string;
id: number
}
export interface ReqQuery {
}
export interface Res {
success: boolean;
}
import { useApi, Put} from "@swordjs/sword-framework";
import { ReqQuery, ReqParams, Res } from "./proto";
export const main = useApi<{
query: ReqQuery;
params: ReqParams;
res: Res;
}>({
instruct: [Put()],
handler: (ctx) => {
return {
success: true,
};
},
});
Delete
删除接口,我们只需要一个id作为参数就可以了:
export interface ReqParams {
id: number;
}
export interface ReqQuery {
}
export interface Res {
success: boolean;
}
import { useApi, Delete } from "@swordjs/sword-framework";
import { ReqQuery, ReqParams, Res } from "./proto";
export const main = useApi<{
query: ReqQuery;
params: ReqParams;
res: Res;
}>({
instruct: [Delete()],
handler: (ctx) => {
return {
success: true,
};
},
});
Query
查询接口,我们希望用户可以用2种方法传递参数,第一种传递方式就是limit/offset,第二种传递方式就是直接传一个page页数,所以需要我们的proto更复杂一点:
export type ReqParams = {
page: number;
} | {
offset: number;
limit: number;
}
export interface ReqQuery {
}
export interface Res {
list: unknown[];
}
我们导出了一个类型别名ReqParams,然后我们就可以在接口中,用上下文直接获取到这些参数,但是请注意当类型别名有多个类型选项时,是没有IDE类型提示的,但是框架的类型校验仍然是有效的:
import { useApi } from "@swordjs/sword-framework";
import { ReqQuery, ReqParams, Res } from "./proto";
export const main = useApi<{
query: ReqQuery;
params: ReqParams;
res: Res;
}>({
handler: (ctx) => {
return {
list: ["test"],
};
},
});
结束
你可以发现,得益于proto,我们编写的api不用再去校验数据的基本类型,它可以确保你的api实现中的参数是安全可靠的,也能给客户端保证每个接口的返回都是严格类型的,解决了很多前后端联调出现的问题。而且我们把proto单独实现,而不和我们的api耦合也是有原因的:
- 不和业务耦合
- 对之后的proto -> api文档,更友好,可以单独的去解析ast
- 可以和前端共享,甚至是生成前端的api代码(类似TSRPC)
Sword.js的类型系统使用了TSRPC的类型系统核心,它不仅支持ts的基本数据类型,还支持ArrayBuffer、Date和一些工具函数,比如Pick, Partial等等