{"id":29704456,"url":"https://github.com/mitmplay/rpc-apitest","last_synced_at":"2025-07-23T14:11:23.952Z","repository":{"id":145837467,"uuid":"617732261","full_name":"mitmplay/rpc-apitest","owner":"mitmplay","description":"Test API isomorphic way from terminal of nodejs or browser ","archived":false,"fork":false,"pushed_at":"2024-09-29T07:43:44.000Z","size":5839,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-03T11:55:33.029Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mitmplay.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-23T01:46:04.000Z","updated_at":"2024-09-29T07:43:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"f9a2660d-8cdb-44b6-8b12-47229e5a0ec0","html_url":"https://github.com/mitmplay/rpc-apitest","commit_stats":null,"previous_names":[],"tags_count":127,"template":false,"template_full_name":null,"purl":"pkg:github/mitmplay/rpc-apitest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitmplay%2Frpc-apitest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitmplay%2Frpc-apitest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitmplay%2Frpc-apitest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitmplay%2Frpc-apitest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mitmplay","download_url":"https://codeload.github.com/mitmplay/rpc-apitest/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitmplay%2Frpc-apitest/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266691595,"owners_count":23969187,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-23T14:11:15.496Z","updated_at":"2025-07-23T14:11:23.943Z","avatar_url":"https://github.com/mitmplay.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RPC Apitest\n\nRPC Apitest - an Isomorphic Rest-client to test API from Web, Nodejs or Browser Console. One of key feature is authoring request with `YAML nested templating`.\n\n`Env` can be set on root template, next YAML nested can have `opt-select`, either unique or multi-select, and before execution(`run`) of request, `opt-run` can be set to override what template provide.\n\nThe templating shared that values across same tree.\n\n# Installation\n```js\nnpm i -g rpc-apitest\n\nrpc-apitest -h\n```\n## Open in http  \n```js\n// -d devmode\n// -o open browser\nrpc-apitest -do // open browser to http://localhost:4001\n\n// debugging server code\nNODE_OPTIONS='--inspect' rpc-apitest -do\nNODE_OPTIONS='--inspect-brk' rpc-apitest -do\n```\n\n## Open in https \u0026 avoid warning: self-sign certificate  \n```js\n// -s open in https\nexport NODE_TLS_REJECT_UNAUTHORIZED=0\nrpc-apitest -dos // open browser to https://localhost:4002\n// or\nNODE_TLS_REJECT_UNAUTHORIZED=0 rpc-apitest -dos\n```\n\n# Tabs - The Web UI\nThe Web UI consist of five tabs:\n* Logs - Show the saved logs after APIs execution\n* Request - The request definition, and run/execute \n* Script (rpc) - Script definition, and run/execute\n* OpenApi - Open Api definition with sample request\n* Docs - Documents in Markdown format\n\n## Logs Tab\nMain functionality is to show the logs after APIs execution, UI interactivity are wired using web-socket, all web-socket connection having Logs auto refresh after each execution(run). There are three type of list (in descending order ): \n* All - No grouping\n* Api - group by api-host\n* Host - group by usr host\n* Date - group by date\n\nEach logs are inside section of: **Request**, **Response Hdr** \u0026 **Response Body**, you can set to auto-expand by checking the checkbox on the action-bar. additional section: **Validate** will appear if request call included Validate definition. \n\n**Yaml checkbox** on the action-bar is to see the logs format in **YAML**\n\nTo download the logs, you can checked the row then click \"Download\" button.\n\nRow also having option to show/hide  **host**, **date** \u0026 **elapsed** (how long API will response), the option are hidden as a popup on the right top screen under checkbox config \"**Limit Header**\". the \"**Show Logs**\" config is auto-change to first tab after API execution.  \n\n## Request Tab\nEach of requests are define using **YAML** file and can having **variable** and **dynamic-var**, this vars are mostly define in template, and the parser will identify vars by seeing words inside curly-braces `{static-var}` hosted in `\\_template\\_.yaml` \u0026 `{{dynamic-var}}` in `\\_template\\_` and to search the value it will use templates:\n\n* `{static-var}` =\u003e `_template_.yaml`\n* `{{dynamic-var}}` =\u003e `_template_.js`\n\nEach `request definition file` will be loaded in the UI and can be tested, as the files is watched!, when you edit the file and save it, it will refresh the UI.\n\n**Parser checkbox** on the action-bar will help (when checked) to see the end result result, but for random value using fake in dynamic vars, the values can be different during the execution of API call.\n\n**Source checkbox** on the action-bar is to see the source code of request \n\n```js\nawait RPC.api.fetch('apidemo/u_agent_post') run\n```\n\u003cdetails\u003e\u003csummary\u003e\u003cb\u003eParser\u003c/b\u003e\u003c/summary\u003e\n\n## Parser\nSome Variable definition in request are reserved for specific purpose:\n\n| var     | description                               |\n|---------|-------------------------------------------|\n| url     | full-path api-url                         |\n| method  | request-method `[get\\|post\\|put\\|delete]` |\n| headers | request-headers                           |\n| params  | query-params `[get]`, injected into `url` |\n| body    | request-body `[post\\|put]`                |\n\n### Dynamic Variables\nCapability of RPC-Apitest to interprate specific string rules (world inside curly-braces) as variable and during parsing, some rules having different meaning on how replacement behave: \n\n#### Simple\nif the world inside curly-braces contains \"strings\" chars without dots.\n```js\ngreet: Hello        // _template_.yaml\n\n...\nbody: {greet}       // request_post.yaml\n\n=\u003e body: Hello      // result\n```\n#### Nested\nmeaning two-things 1) the definition is nested and want to access specific value, the world inside curly-braces need to reach the nested using \"dots\" separator -OR- 2) its a simple parser way with result of replacement will be nested.\n```js\ngreet:              // _template_.yaml\n  nice: Hi Alice\n\n...\nbody: {greet.nice}  // request_post.yaml\n\n=\u003e body: Hi Alice\n\n...\nbody: {greet}       // request_post.yaml\n\n=\u003e body:\n     nice: Hi Alice // result\n```\n#### Shorthand `{\u0026}`\nAmpersand will denotate the current key, ie: below show how it works during the parser\n```js \ngreet:              // _template_.yaml\n  body: Howdy John\n\n...\nbody: {greet.\u0026}     // request_post.yaml\n~\u003e    {greet.body}\n\n=\u003e body: Howdy John // result\n```\n#### Spread\nBasic meaning is to replace the key with the nested values\n```js\nnames:              // _template_.yaml\n  first: John\n  last: Doe\n\n...\nbody:               // request_post.yaml\n  _1: '{...names}'\n\n=\u003e body:            // result\n    first: John\n    last: Doe\n```\n### Inject on specific key\nwhen **the Spread** words contain tilde \"~\" after it, its a key that need to search and do merged values.\n```yaml\n_validate: \n  -@:\n    id: true\n    userId: true\n    title: true \n  response:\n    200: 'records'\n\n_body~-@:\n  userId: false\n  body: true\n\nruns:\n  validate~1: \n    _1: '{..._validate}'\n  validate~2:\n    _1: '{..._validate}'\n    _2: '{..._body~-@}'\n\n=\u003e\nruns:\n  validate~1: \n    -@:\n      id: true\n      userId: true\n      title: true \n    response:\n      200: 'records'\n  validate~2:\n    -@:\n      id: true\n      userId: false\n      title: true \n      body: true\n    response:\n      200: 'records'\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cb\u003eFunction Parser\u003c/b\u003e\u003c/summary\u003e\n\n## Function Parser\nFunction parser is a special `\\_template\\_.js` to host functions and it can use inside request as `{{dynamic-var}}`:\n```js\nmodule.exports = $ =\u003e ({ // _template_.js\n  first: _ =\u003e rpc()._lib_.chance.first(),\n  dtnow: _ =\u003e `{greet-ed} ${(new Date()).toISOString()}`,\n})\n\nbody: {{now}}            // request_post.yaml\n=\u003e body: 2023-04-20T07:34:57.092Z\n``` \n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cb\u003e_template_.yaml\u003c/b\u003e\u003c/summary\u003e\n\n### Example of ROOT `_template_.yaml`\n```yaml\nbaseurl: http://baseurl.com\n\nenv:\n  dev:\n    greet: '{baseurl}/hello from DEV'\n  qa: \n    greet: '{baseurl}/hello from QA'\n  noreplace: 'no change on vars'\n\ndefault:\n  method: get\n  headers:\n    Content-Type: application/json\n\ngreet: Hi from non ENV\ngreet-ed: hello\n\nmainurl: '{baseurl}/woo'\ndate: '{{dtnow}}'\n```\n### Example after ROOT `_template_.yaml`\n\n```yaml\nselect:\n  w-me:\n    me: 'its me'\n  s~one:\n    greet: howdy one\n  s~two:\n    greet: howdy two\n```\n**env:** on the root \\_template\\_ will determine which var will be taken presedence over regular one. the **Active Env** is visible on the UI as it show on the right-side of **the root \\_template\\_**. you can see var getting replaced by checking the `Parser` option on action-bar. Example below on `greet` var the posibility of values getting replaced:\n```yaml\n# env: dev\ngreet: 'http://baseurl.com/hello from DEV'\n\n# env: qa\ngreet: 'http://baseurl.com/hello from QA'\n\n# env: noreplace\ngreet: 'Hi from non ENV'\n\n# select: one\ngreet: howdy one\n``` \n**select:**/(**slc**) if selection is set, it will take precedence over (**env**) as show in last example when select set to **s~one** the greet value change to 'howdy one'. **text with tilde** is identified for unique selection.\n\n**default:** on the root \\_template\\_ will be used on request definition\n```yaml\n# test.yaml\nurl: '{baseurl}/hello'\n```\nParsed values:\n```yaml\nurl: 'http://baseurl.com/hello'\nheaders:\n  method: get\n  Content-Type: application/json\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cb\u003eChance faker\u003c/b\u003e\u003c/summary\u003e\n\n## Chance faker\nBuilt in Function Parser to generate random faker, you can visit [Chance website](https://chancejs.com/)\n```js\nbody: {{chance.address}} // request_post.yaml\n=\u003e body: 908 Cezkaw Junction\n``` \nUse Chrome Console browser to test `chance faker`\n```js\nawait RPC.api.chance('name')\nawait RPC.api.chance('address')\nawait RPC.api.chance('cc', {type: 'mc'})\nawait RPC.api.chance('cc', {type: 'visa'})\nawait RPC.api.chance('paragraph', { sentences: 1 })\n```\n\u003c/details\u003e\n\n## Script / RPC call\nOpen Chrome Devtools Console, test it by copy paste one line and execute\n\nor you can try from UI `Tab:Script` \n```js\nawait RPC.apidemo.demo_add()  //# no broadcast \nawait RPC.apidemo.api_yesno() //# triggering broadcast\n```\n\nAll api start with: `'.api_'` will trigger broadcast message\n```js\nawait RPC.apidemo.api_yesno()   \nawait RPC.apidemo.api_u_agent() \n\nvar ua= 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:111.0) Gecko/20100101 Firefox/111.0'\nawait RPC.apidemo.api_u_agent({body:{ua}})\n\n// special namespace: api...\nawait RPC.api.peek()\nawait RPC.api.fetch({\n  url: \"https://api.apicagent.com/\",\n  method: \"post\",\n  headers: {\n    \"Content-Type\": \"application/json\"\n  },\n  body: {ua}\n})\n```\n## OpenApi \u0026 mock server\n\nWhen you have OpenAPI difinition YAML, you can drop it to your home folder: `~/user-rpc/apidemo/openapi` \n```js\nnpm install -g @stoplight/prism-cli\nprism mock https://raw.githack.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore.yaml\n\n// test the OpenApi mock server with fetch function\nawait RPC.api.fetch({\n  url: \"http://127.0.0.1:4010/pets\",\n  method: \"get\",\n  headers: {\n    \"Content-Type\": \"application/json\",\n    api_key: \"123\"\n  }\n})\n\n// use mock definition visible on the UI Tab:OpenApi\nawait RPC.api.fetch('apidemo/openapi[get]/pet')\n```\n\n# Folder Structure\n```js\n// default folder at home: ~/user-rpc/name_space/type/files, ie:\n* ~/user-rpc/apidemo/docs/readme.md             // markdown file for documentation\n* ~/user-rpc/apidemo/openapi/some_openapi.yaml  // YAML file OpenAPI definition\n* ~/user-rpc/apidemo/request/some_api_req.yaml  // YAML file request definition\n* ~/user-rpc/apidemo/script/script1.js          // Javascript file\n\n// you can change the path using CLI option:\n// -r=~/proj/apidemo     OR \n// --rpcpath=~/proj/apidemo\n* ~/proj/apidemo/docs/readme.md             // markdown file for documentation\n* ~/proj/apidemo/openapi/some_openapi.yaml  // YAML file OpenAPI definition\n* ~/proj/apidemo/request/some_api_req.yaml  // YAML file request definition\n* ~/proj/apidemo/script/script1.js          // Javascript file\n```\n\n# Registering `broadcast event`: \n```js\nconst fn = x =\u003e console.log(x)\nRPC._broadcast_._any_.fn = fn\nRPC._broadcast_['apidemo.api_yesno'] = fn\n```\n\n# Unable to verify the first certificate\n`Error: unable to verify the first certificate` means that the web server is misconfigured and didn't send the intermediate certificates. if you have the certificate, you can set the NODE_EXTRA_CA_CERTS environment variable\n\n```js\nexport NODE_EXTRA_CA_CERTS='some_extra_certs.pem'\n```\nor if follow with `UNABLE_TO_VERIFY_LEAF_SIGNATURE` try to set environment variable\n```js\nexport NODE_TLS_REJECT_UNAUTHORIZED=0\n```\n\n# Public API\nSome sample of public APIs:\n* https://apis.guru/\n* https://xkcd.com/json.html\n\n\u003cbr/\u003e\n\u003chr/\u003e\n\n*`wh`!* \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmitmplay%2Frpc-apitest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmitmplay%2Frpc-apitest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmitmplay%2Frpc-apitest/lists"}