公司的前后端都是通过同一份接口定义文件去生成接口代码,前期用的是 thrift,后面转成 protobuf。基本的流程像下面这样
thrift/protobuf => Go/TypeScript/Java/Swift
当接口需要修改的时候,实际是去修改定义好的这份文档,然后各端再重新生成一下代码。整个流程,用过的人都觉得爽。
在开发的时候,前端经常会遇到另外一个问题,需要等后端把接口写完才开始写页面,不然的话就只能先自己在页面手动写一些假数据。因为我们是用 TypeScript,所以实际已经是知道接口返回哪些字段,并且字段是什么类型。所以,是不是可以根据这些信息自动去生成假数据呢?
根据这样的思路,便写了一个 express 中间件,ezmok。对于为什么不是叫 ezmock 呢,因为这个名字在 npm 上面已经被注册了。:(
先说下最重要的数据生成部分。一开始打算用 TS 的 api 去分析生成的代码,因为之前逛知乎的时候,知道有个叫 json schema 的东西。查了一下,感觉像是发现了新大陆。社区已经有很多现成的库来满足我所有的需求。
typescript-json-schema
json-schema-faker
react-jsonschema-form
可以根据 JSON Schema 自动生成表单,支持填充进数据,这样就可以很方便地编辑事先生成好的假数据具体的代码,服务器端获取 schema 部分
import * as TJS from "typescript-json-schema";
export async function getAPISchema(apiPath: string): Promise<TJS.Definition | null> {
// 获取具体的定义文件路径
const fileInfo = await getAPIFileInfo(apiPath);
// 获取接口返回参数信息
const typeName = await getTypeName(fileInfo);
// 分析整个文件
const program = TJS.getProgramFromFiles([fileInfo.path]);
// 找到接口返回信息对应的 schema
const schema = TJS.generateSchema(program, typeName.name, {
ignoreErrors: true,
required: true
});
return schema;
}
客户端根据 schema 生成数据
import * as jsf from "json-schema-faker";
function genFakeData(schema) {
return jsf.resolve(schema);
}
根据 schema 和数据生成表单
import Form from "react-jsonschema-form";
class SchemaForm extends React.PureComponent<SchemaFormProps, {}> {
onSubmit = e => {
this.props.onSubmit(e.formData);
};
render() {
const { schema, formData, generateData } = this.props;
const widgets = {
BaseInput: BaseInputWidget,
SelectWidget,
CheckboxWidget
};
// simply update to draft-6....
const schemaV6 = Object.assign({}, schema, {
$schema: "http://json-schema.org/draft-06/schema#"
});
return (
<Form
schema={schemaV6}
widgets={widgets}
FieldTemplate={SchemaTemplate}
ArrayFieldTemplate={ArrayFieldTemplate}
onSubmit={this.onSubmit}
formData={formData}
>
<div style={{ textAlign: "center" }}>
<Button style={{ marginRight: 20 }} onClick={generateData}>
重新生成数据
</Button>
<Button type="primary" htmlType="submit">
提交
</Button>
</div>
</Form>
);
}
}
react-jsonschema-form
最简单的用法就是把 schema 和数据传过去就行。从上面的代码也可以看到,这个库还是非常灵活,支持自定义各种 widget 和 template。
上面就是数据的生成和管理部分。除此之外,还需要判断哪些路径是需要 mock 的,所以大致的中间件就像下面这样
const EZMOK_PREFIX = "/ezmok";
function ezmokMiddleware() {
const jsonParser = bodyParser.json();
jsonParser(req, res, afterParseJSON);
function afterParseJSON() {
const apiPath = req.path;
if (apiPath.startsWith(EZMOK_PREFIX)) {
// ezmok 相关的功能
if (req.method === "GET") {
// 如果是 Get 请求,则返回 ezmok 的后台界面
} else {
// 相关的接口调用,比如生成 schema 之类的
}
} else {
// 实际的业务接口调用
const mockData = globalSetting.getMockData();
if (mockData.path.includes(apiPath)) {
// 知道这个接口要 mock,返回对应的数据
} else {
// 这部分的接口不用 mock,重定向到真正的接口地址
res.redirect(
307,
realAPIHost
);
}
}
}
}
因为这个中间件的代码很多是和公司内部的技术栈耦合,所以源码就没有放到 github 上面,有兴趣的可以直接到 npm 看看。
(完)