V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
jasonkayzk
V2EX  ›  分享创造

用 TypeScript 写了一个 Mock Protobuf 的 CLI 工具

  •  1
     
  •   jasonkayzk ·
    JasonkayZK · 2022-10-09 10:43:38 +08:00 · 1708 次点击
    这是一个创建于 774 天前的主题,其中的信息可能已经有所发展或是发生改变。

    用 TypeScript 写了一个 Mock Protobuf 的工具

    使用

    使用 npm 安装:

    npm i mock-pb-cli@latest -g
    

    可以使用下面命令查看帮助:

    $ mock-pb -h
    
    Usage: mock-protobuf [options] [command]
    
    A tool to mock protobuf
    
    Options:
      -v, --version         output the version number
      -h, --help            display help for command
    
    Commands:
      s|serve [options]     Create a mock server for the given protobuf
      g|generate [options]  Generate mock data for the given protobuf
      help [command]        display help for command
    

    有两个子命令:

    • mock-pb gmock-pb generate:Mock JSON 数据;
    • mock-pb s or mock-pb serve:Mock 服务;

    Mock JSON 数据

    Generate 子命令主要是用来生成 Mock 的 JSON 数据;

    例如:

    $ mock-pb g
    

    上面的命令会获取当前工作目录下所有的 Proto 文件,并且将 Mock 的数据输出到终端;

    例如:

    Mocked demo.BasicResponse:
    {
        "status": 902735693509892,
        "message": "Vmucue hqxllqx oiloapzwp.",
        "resp": {}
    }
    
    Mocked demo.DemoRequest:
    {
        "data": "Kqr gxxq."
    }
    
    Mocked demo.DemoResponse:
    {
        "resp": {
            "status": -6061376970430480,
            "message": "Xpjzjyxrcq eqkmytjo.",
            "resp": {}
        },
        "resp_data": "Ryogd tswayqjsf."
    }
    

    默认情况下的 Protobuf 文件搜索路线为 .,你也可以使用 -d 来指定路径!

    例如:

    $ mock-pb g -d ../test/proto
    

    同时,默认情况下 Mock 数据会打印到终端,你也可以使用 -o 来指定将 Mock 的数据输出到指定的目录!

    例如:

    $ mock-pb g -o ./mock-pb-output
    

    此时,mock-pb-output 目录下的结果为:

    $ tree
    .
    ├── demo
    │   ├── BasicResponse.json
    │   ├── DemoRequest.json
    │   └── DemoResponse.json
    ├── google.api
    │   ├── CustomHttpPattern.json
    │   ├── HttpBody.json
    │   ├── Http.json
    │   └── HttpRule.json
    └── google.protobuf
        ├── Any.json
        ├── Api.json
    		......
        ├── SourceContext.json
        ├── Type.json
        └── UninterpretedOption.json
    

    输出中的目录结构是根据 Proto 文件中的 package 来产生的!


    Mock 服务

    基本用法

    除了产生 Mock 的数据,也可以直接 Mock 服务接口;

    下面的命令会读取当前工作目录下的 Proto 文件,并 Mock 在 Service 中定义了的 Method:

    $ mock-pb s
    

    输出如下:

    Handling routePath: /Demo
    Handling routePath: /demo/DemoServiceAnotherDemo
    restify listening at http://[::]:3333
    

    在服务端启动时,会打印出每个接口的请求路径;

    默认情况下的服务端口号为:3333,你可以使用 -p 来自定义端口;

    例如:

    • mock-pb s -p 13333

    如果你在你的 Method 中通过 google.api.http 定义了请求路径,那么在 Mock 服务的时候会使用这个路径;

    例如:

    service DemoService {
      rpc Demo(DemoRequest) returns (DemoResponse) {
        option (google.api.http) = {
          post: "/Demo"
          body: "*"
        };
      }
    }
    

    如果没有指定请求路径,那么请求路径为:/{ProtobufPackageName}/{ProtobufMethodName}

    例如:

    syntax = "proto3";
    
    package demo;
    
    service DemoService {
      rpc AnotherDemo(AnotherDemoRequest) returns (AnotherDemoResponse) {}
    }
    

    当服务启动后的请求路径为:

    $ curl localhost:3333/demo/DemoServiceAnotherDemo
    {"resp":{"status":-843357854531144,"message":"Vzby.","resp":{}},"resp_data":"Kvia gfkcggmuo."}
    

    自定义返回值

    有时候你可能并不想 Mock 一些像下面这些无意义的数据:

    {"resp":{"status":-843357854531144,"message":"Vzby.","resp":{}},"resp_data":"Kvia gfkcggmuo."}
    

    而是想要自定义一些有用的返回值,比如:

    {"resp":{"status":200,"message":"ok"},"resp_data":{"Message":"This is a demo message"}}
    

    此时可以创建配置文件,例如:

    mock-protobuf.config.json

    {
        "ResponseValue": [
            {
                "MethodName": "demo.Demo",
                "Data": {
                    "Hello": "world"
                }
            },
            {
                "MethodName": "demo.AnotherDemo",
                "Data": {
                    "resp": {
                        "status": 200,
                        "message": "ok"
                    },
                    "resp_data": {
                        "Message": "This is a demo message"
                    }
                }
            }
        ]
    }
    
    

    其中 MethodName 是 Proto 文件中 Method 的全名:package.method

    同时,你也可以通过 -c 请求来指定你的配置文件路径,例如: -c ./mock-protobuf.config.json

    下面是一个完整的命令行例子:

    $ npm run dev -- s -i demo -c ./mock-protobuf.config-demo.json
    

    使用自定义返回值后的响应如下:

    $ curl localhost:3333/Demo
    {"Hello":"world"}
    
    $ curl localhost:3333/demo/DemoServiceAnotherDemo
    {"resp":{"status":200,"message":"ok"},"resp_data":{"Message":"This is a demo message"}}
    

    过滤条件

    有的时候我们并不想 Mock 所有的 Proto 定义,此时可以使用 Filter 过滤条件;

    有两种方式进行过滤:

    • 包含 Includes: -i <string>--include;
    • 不包含 Excludes: -e <string>--exclude;

    上面的 <string> 被定义为一个 JS 中的正则表达式 RegExp,所以可以使用类似于正则表达式的方式对 Proto 定义进行匹配:packageName.serviceName.methodName

    多个条件使用 , 分隔!


    Include 过滤条件

    当使用 Include 过滤条件,只有匹配的 Proto 定义才会被 Mock ;

    例如:

    $ mock-pb g -i demo
    
    Mocked demo.BasicResponse:
    {
        "status": -978663427598816,
        "message": "Iymo zomttydmb.",
        "resp": {}
    }
    
    Mocked demo.DemoRequest:
    {
        "data": "Mdnbfxbvoq khrbwyu sxmkev jss."
    }
    
    Mocked demo.DemoResponse:
    {
        "resp": {
            "status": 6207610394471496,
            "message": "Dkwse mmhmuhhunb.",
            "resp": {}
        },
        "resp_data": "Fqwkd noiefpr ntjbcfydl."
    }
    
    Mocked demo.AnotherDemoRequest:
    {
        "name": "Puvujqy kyxl hshuysly.",
        "age": 175838119803604
    }
    
    Mocked demo.AnotherDemoResponse:
    {
        "resp": {
            "status": -7659482750118844,
            "message": "Fygec kyzysqqga svimupy nbfrjt.",
            "resp": {}
        },
        "resp_data": "Mpgjtjsbr qfspgkb xmpji."
    }
    

    上面的命令只会为 demo.* 产生 Mock 数据(即:package 为 demo 的那些定义)!

    另外一个例子:

    $ mock-pb g -i demo.DemoRequest.*
    
    Mocked demo.DemoRequest:
    {
        "data": "Ewqzspj hjkfvvc froqdhkwe fkqsdg dytidwli."
    }
    

    此时只会 Mock:demo.DemoRequest 这一个 Message !


    Exclude 过滤条件

    相反的,-e 产生将会排除那些匹配的 Message ;

    例如:

    $ mock-pb g -e demo.*,google.protobuf.* -o mock-pb-gen
    
    $ tree
    .
    └── google.api
        ├── CustomHttpPattern.json
        ├── HttpBody.json
        ├── Http.json
        └── HttpRule.json
    

    上面的命令将不会 Mock demo.*google.protobuf.* 下的 Message !

    <font color="#f00">注意:当你同时使用 include and exclude 两个过滤器,exclude 会永远首先生效!</font>

    例如:

    $ mock-pb g -i demo -e demo
    

    什么都不会输出,因为所有的内容都被过滤掉了!


    关于整个开发的过程以及思路,我也放到了我的博客:

    希望对 TypeScript 初学者,以及想使用 TypeScript 编写 CLI 小工具的小伙伴们有帮助!❤️

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3030 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 13:04 · PVG 21:04 · LAX 05:04 · JFK 08:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.