{"id":37221528,"url":"https://github.com/jirenius/rest2res","last_synced_at":"2026-01-15T01:26:38.888Z","repository":{"id":95678652,"uuid":"185218061","full_name":"jirenius/rest2res","owner":"jirenius","description":"A NATS/RES service turning legacy REST APIs into live APIs served through Resgate.","archived":false,"fork":false,"pushed_at":"2019-05-06T14:58:34.000Z","size":14,"stargazers_count":13,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-06-21T17:02:31.477Z","etag":null,"topics":["go","golang","microservices","nats-server","realtime","resgate","rest-api"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jirenius.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":"2019-05-06T14:56:08.000Z","updated_at":"2023-08-24T18:47:50.000Z","dependencies_parsed_at":"2023-03-31T05:12:40.802Z","dependency_job_id":null,"html_url":"https://github.com/jirenius/rest2res","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jirenius/rest2res","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jirenius%2Frest2res","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jirenius%2Frest2res/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jirenius%2Frest2res/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jirenius%2Frest2res/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jirenius","download_url":"https://codeload.github.com/jirenius/rest2res/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jirenius%2Frest2res/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28441031,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-15T00:55:22.719Z","status":"ssl_error","status_checked_at":"2026-01-15T00:55:20.945Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["go","golang","microservices","nats-server","realtime","resgate","rest-api"],"created_at":"2026-01-15T01:26:38.197Z","updated_at":"2026-01-15T01:26:38.872Z","avatar_url":"https://github.com/jirenius.png","language":"Go","readme":"\u003cp align=\"center\"\u003e\u003ca href=\"https://resgate.io\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cimg width=\"100\" src=\"https://resgate.io/img/resgate-logo.png\" alt=\"Resgate logo\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\u003ch2 align=\"center\"\u003e\u003cb\u003eREST to RES service\u003c/b\u003e\u003cbr/\u003eSynchronize Your Clients\u003c/h2\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n\u003ca href=\"http://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\" alt=\"License\"\u003e\u003c/a\u003e\n\u003ca href=\"http://goreportcard.com/report/jirenius/rest2res\"\u003e\u003cimg src=\"http://goreportcard.com/badge/github.com/jirenius/rest2res\" alt=\"Report Card\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n*REST to RES* (*rest2res* for short) is a service for [Resgate](https://resgate.io) and [NATS Server](https://nats.io) that can turn old JSON based legacy REST APIs into live APIs.\n\nVisit [Resgate.io](https://resgate.io) for more information on Resgate.\n\n## Polling madness\nDo you have lots of clients polling every X second from your REST API, to keep their views updated? This is madness :scream:!\n\nBy placing *rest2res/resgate* in between as a cache, you can reduce thousands of polling clients to a single *rest2res* service doing the polling on their behalf.\n\nThe clients will instead fetch the same data from *Resgate*, whose cache is efficiently updated by *rest2res* whenever there is a modification. No changes has to be made to the legacy REST API, nor the clients (except perhaps changing which URL to poll from).\n\nYour clients can later be improved to use [ResClient](https://www.npmjs.com/package/resclient), which uses WebSocket, to reliably get the updates as soon as they are detected, without having to do any polling at all. This will majorly decrease the bandwidth required serving your clients.\n\n ## Quickstart\n\n### Download Resgate/NATS Server\nThis service uses *Resgate* and *NATS Server*. You can just download one of the pre-built binaries:\n* [Download](https://nats.io/download/nats-io/gnatsd/) and run NATS Server\n* [Download](https://github.com/jirenius/resgate/releases/latest) and run Resgate\n\n\u003e **Tip**\n\u003e\n\u003e If you run Resgate with:  `resgate --apiencoding=jsonflat`  \n\u003e the web resource JSON served by Resgate will look the same as the legacy REST API for nested JSON structures, without href meta data.\n\n### Build rest2res\n\nFirst make sure you have [installed Go](https://golang.org/doc/install). Then you can download and compile the service:\n\n```text\ngit clone github.com/jirenius/rest2res\ncd rest2res\ngo build\n```\n\n### Try it out\n\nRun it with one of the example configs, such as for *worldclockapi.com*:\n```text\nrest2res --config=examples/clock.config.json\n```\n\nAccess the data through Resgate:\n\n```text\nhttp://localhost:8080/api/clock/utc/now\n```\n\nOr get live data using [ResClient](https://resgate.io/docs/writing-clients/resclient/):\n\n```javascript\nimport ResClient from 'resclient';\n\nlet client = new ResClient('ws://localhost:8080');\nclient.get('clock.utc.now').then(model =\u003e {\n   console.log(model.currentDateTime);\n   model.on('change', () =\u003e {\n      console.log(model.currentDateTime);\n   });\n});\n```\n\n## Usage\n```text\nrest2res [options]\n```\n\n| Option | Description | Default value\n|---|---|---\n| `-n, --nats \u003curl\u003e` | NATS Server URL | `nats://127.0.0.1:4222`\n| `-c, --config \u003cfile\u003e` | Configuration file (required) |\n| `-h, --help` | Show usage message |\n\n\n## Configuration\n\nConfiguration is a JSON encoded file. It is a json object containing the following available settings:\n\n**natsUrl** *(string)*  \nNATS Server URL. Must be a valid URI using `nats://` as schema.  \n*Default:* `\"nats://127.0.0.1:4222\"`\n\n**serviceName** *(string)*  \nName of the service, used as the first part of all resource IDs.  \n*Default:* `rest2res`\n\n**externalAccess** *(boolean)*  \nFlag telling if access requests are handled by another service. If false, rest2res will handle access requests by granting full access to all endpoints.  \n*Default:* `false`\n\n**endpoints** *(array of endpoints)*  \nList of endpoints handled by rest2res. See below for [endpoint configuration](#endpoint).  \n*Default:* `[]`\n\n\u003e **Tip**\n\u003e\n\u003e A new configuration file with default settings can be created by using the `--config` option, specifying a file path that does not yet exist.\n\u003e\n\u003e ```text\n\u003e rest2res --config myconfig.json\n\u003e ```\n\n### Endpoint\n\nAn endpoint is a REST endpoint to be mapped to RES. It is a json object with the following available settings:\n\n**url** *(string)*  \nURL to the legacy REST API endpoint. May contain `${tags}` as placeholders for URL parameters.  \n*Example:* `\"http://worldclockapi.com/api/json/${timezone}/now\"`\n\n**refreshTime** *(number)*  \nThe duration in milliseconds between each poll to the legacy endpoint.  \n*Default:* `5000`\n\n**refreshCount** *(number)*  \nNumber of times *rest2res* should poll a resource before asking Resgate(s) if any client is still interested in the data.  \nA high number may cause unnecessary polling, while a low number may cause additional traffic between rest2res and Resgate.  \n*Default:* `6`\n\n**timeout** *(number)*  \nTime in milliseconds before client requests should timeout, in case the endpoint is slow to respond. If `0`, or not set, the default request timeout of Resgate is used.  \n*Example:* `5000`\n\n**type** *(string)*  \nType of data for the legacy endpoint. The setting tells *rest2res* if it should expect the legacy endpoint to return an *object* or an *array*.\n\n* `model` - used for a JSON objects\n* `collection` - used for a JSON arrays\n\n*Example:* `\"model\"`\n\n**pattern** *(string)*  \nThe resource ID pattern for the endpoint resource.  \nThe pattern often follows a similar structure as the URL path, but is dot-separated instead of slash-separated. A part starting with a dollar sign is considered a placeholder (eg. `$tags`). The pattern must contain placeholders matching the placeholder names used in the endpoint *url* setting.  \n*Example:* `\"$timezone.now\"`\n\n**resources** *(array of resources)*  \nList of nested resources (objects and array) within the endpoint root data. See below for [resource configuration](#resource).  \n*Example:* `[{ \"type\":\"model\", \"path\":\"foo\" }]`\n\n### Resource\n\nA resource, in this context, is an object or array nested within the endpoint data. It is called *resource* as it will be mapped to its own [RES resource](https://resgate.io/docs/writing-services/02basic-concepts/#resources) with a unique *resource ID*. The configuration is a JSON object with following available settings:\n\n**type** *(string)*  \nType of data for the sub-resource.\n\n* `model` - used for a JSON objects\n* `collection` - used for a JSON arrays\n\n*Example:* `\"model\"`\n\n**pattern** *(string)*  \nThe resource ID pattern for the sub-resource.  \nMay be omitted. It omitted, the pattern will be the same as the parent resource pattern suffixed by the *path* setting.  \n*Example:* `\"station.$stationId.transfers\"`\n\n**path** *(string)*  \nThe path to the resource relative to the parent resource.  \nIf the parent resource is an object/model, the *path* is either:\n\n* name of the parent property key (eg. `\"foo\"`)\n* a placeholder starting with `$`, acting as a wildcard for all parent property keys (eg. `\"$property\"`).  \n\nIf the parent resource is an array/collection, the *path* is a placeholder starting with `$` (eg. `$userId`). The placeholder represents either:\n\n* index in the parent array\n* model id, in case `idProp` is set (see below).\n\n**idProp** *(string)*  \nID property in an object, used to identify it within a parent array/collection.  \nOnly valid for *object* types.  \n*Example:* `\"_id\"`\n\n**resources** *(array of resources)*  \nList of nested [resources](#resource) (objects and array) within the sub-resource.  \n*Example:* `[{ \"type\":\"model\", \"path\":\"bar\" }]`\n\n\u003e **Tip**\n\u003e\n\u003e Does configuring an endpoint seem complicated?  \n\u003e Check out the example configs in the [`/examples`](examples/) folder.\n\n## Caveats\n\nThe data fetched by *rest2res* will be shared through Resgate's cache with all clients requesting the same data. This means that the legacy REST API endpoints must be completely open for *rest2res* to access, as it will never access a legacy REST endpoint on behalf of a specific client.\n\n**Authorization**  \nIf client authorization is needed, this can be handled by creating a separate authentication and authorization service. Read more about [access control on Resgate.io](https://resgate.io/docs/writing-services/07access-control/).\n\n**User specific data**  \nWhile it is possible to have user specific resources, *rest2res* does not support having a single endpoint URL returning different data depending on which user accesses it.  \nBut seriously, no proper REST resource should return different results on the same URL.\n\n\n## Contribution\n\nIf you find any issues with the service, feel free to report them. This project caters to some specific needs, and may yet lack features to make it viable for all use cases.\n\nIf you lack a feature, feel free to create an issue for it to be discussed. If you like coding in Go, maybe you can make a pull request with the solution concluded from the discussion.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjirenius%2Frest2res","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjirenius%2Frest2res","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjirenius%2Frest2res/lists"}