{"id":21291819,"url":"https://github.com/testingrequired/restfile","last_synced_at":"2026-03-19T19:43:43.466Z","repository":{"id":44380917,"uuid":"466963397","full_name":"testingrequired/restfile","owner":"testingrequired","description":"restfile is a specification for storing HTTP requests in an easy to read and write file format.","archived":false,"fork":false,"pushed_at":"2022-11-11T21:47:59.000Z","size":389,"stargazers_count":3,"open_issues_count":14,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-01-22T06:28:18.158Z","etag":null,"topics":["api","api-tools","http","rest","specification","testing-tools"],"latest_commit_sha":null,"homepage":"https://testingrequired.github.io/restfile/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/testingrequired.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-03-07T06:02:22.000Z","updated_at":"2023-01-08T17:16:41.000Z","dependencies_parsed_at":"2023-01-21T12:31:19.693Z","dependency_job_id":null,"html_url":"https://github.com/testingrequired/restfile","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testingrequired%2Frestfile","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testingrequired%2Frestfile/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testingrequired%2Frestfile/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testingrequired%2Frestfile/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/testingrequired","download_url":"https://codeload.github.com/testingrequired/restfile/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243762227,"owners_count":20343972,"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","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":["api","api-tools","http","rest","specification","testing-tools"],"created_at":"2024-11-21T13:46:18.085Z","updated_at":"2026-03-19T19:43:43.421Z","avatar_url":"https://github.com/testingrequired.png","language":"TypeScript","readme":"# 💤📄 _restfile_\n\n[![restfile](https://github.com/testingrequired/restfile-ts/actions/workflows/ci.yml/badge.svg)](https://github.com/testingrequired/restfile-ts/actions/workflows/ci.yml)\n\nrestfile is a specification for storing HTTP requests in an easy to read and write file format.\n\n## Features\n\n- HTTP request messages as [requests](#requests)\n- HTTP response messages as [tests](#tests)\n- [Templating](#templating) in [requests](#requests) with [variables](#environmental-data), [prompts](#prompts), [secrets](#secrets), and [references](#references)\n\n## Goals\n\n- Easy to read, write\n- Flatter structure\n- Limited templating syntax\n- Diff friendly\n\n## Format\n\nA restfile is a [multi-document](https://yaml.org/spec/1.2.1/#marker/directives%20end/) [YAML](https://yaml.org/) file.\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\n# Information Document\n\nname: Example User API\ndescription: Descriptions are optional but helpful.\nenvs: [local, prod]\n---\n# Data Document\n\nbaseUrl: !!str #Variable\nsecretAccessToken!: !!str #Secret\n\n# Environmental Values\nlocal:\n  baseUrl: http://localhost\nprod:\n  baseUrl: https://api.insertcompanyname.com\n---\n# Request Document\nid: get-users\ndescription: Get all users\nhttp: |+\n  GET {{$ baseUrl}}/users HTTP/1.1\n  Authorization: Bearer {{! secretAccessToken}}\n\n\n---\n# Request Document\nid: get-user-by-id\ndescription: Get user by id\nprompts:\n  userId: !!str\nhttp: |+\n  GET {{$ baseUrl}}/users/{{? userId}} HTTP/1.1\n  Authorization: Bearer {{! secretAccessToken}}\n\n\n---\n# Addition Request Documents...\n```\n\n### Information\n\nThe `information` document is the first document in the restfile. It's required and defines the `name`, `description` and a list of enviroment names `envs`.\n\n```typescript\ninterface InformationDocument {\n  name: string;\n  description?: string;\n  envs: string[];\n}\n```\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\nname: Example User API\ndescription: Descriptions are optional but helpful.\nenvs: [local, prod]\n```\n\n### Data\n\nThe `data` document is the second document. It allows you to define variables and [secrets](#secrets) available for templating in requests.\n\n```typescript\ntype DataDocument = Record\u003cstring, unknown\u003e;\n```\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\nbaseUrl: http://localhost\nuserId: 99\n\nsecretAccessToken!: !!str\n```\n\n#### Environmental Data\n\nVariables can also be assigned enviroment based values.\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\n# Information Document\n\nname: Data Example\nenvs: [local, prod]\n---\n# Data Document\n\nbaseUrl: !!str # You can also use an empty string e.g. \"\"\n\nlocal:\n  baseUrl: http://localhost\nprod:\n  baseUrl: http://example.com\n---\n```\n\nEnvironment name keys defining variable values but be defined in the environment names `envs` in the `information` document. Otherwise this will cause validation errors.\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\nname: Data Example\nenvs: [local, prod]\n---\nbaseUrl: !!str\n\nlocal:\n  baseUrl: http://localhost\nprod:\n  baseUrl: http://example.com\ninvalidEnv:\n  baseUrl: \"This will cause validation errors\"\n---\n```\n\nVariables referenced in environment based values must be defined at the root of the `data` document. Otherwise this will cause validation errors.\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\nname: Data Example\nenvs: [local, prod]\n---\nbaseUrl: !!str\n\nlocal:\n  baseUrl: http://localhost\n  invalidVariable: \"This will cause validation errors\"\nprod:\n  baseUrl: http://example.com\n---\n```\n\n#### Secrets\n\nSecrets `{{! secretName}}` are variables that are populated at runtime. They must be defined in the `data` document with a name appended with `!` e.g. `token!` in data, `{{! token}}` while templating\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\nname: Secrets Example\nenvs: []\n---\ntoken!: !!str\n---\nid: example\nhttp: |+\n  GET https://example.com HTTP/1.1\n  Authorization: Bearer {{! token}}\n\n\n```\n\nThe difference from prompts is that secrets aren't provided by the user but programatically e.g. AWS Secrets Manager.\n\n### Requests\n\nAll remaining documents in the restfile are request doucments.\n\n```typescript\ninterface RequestDocument {\n  id: string;\n  description?: string;\n  auth: Record\u003cstring, string\u003e;\n  prompts?: Record\u003cstring, string | { default: string }\u003e;\n  http: string;\n  tests?: Record\u003cstring, string\u003e;\n}\n```\n\nRequests require both an `id`, and `http` request string at a minimum.\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\nname: Example\ndescription: Show what a bare but complete restfile and request look like\nenvs: []\n---\n\n---\n# Example Request\nid: get-ip\nhttp: |+\n  GET https://get.geojs.io/v1/ip.json HTTP/1.1\n\n\n```\n\nThe `request.http` value must be a valid HTTP request message or an error will be thrown during request execution. It's particularly sensitive around newlines after the headers and body.\n\nAs part of the spec these requirements should be looser allowing for requests like this:\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\nname: Example\nenvs: []\n---\n\n---\n# Example Request\nid: get-ip\n# This will error currently because of the lack of newlines\nhttp: GET https://get.geojs.io/v1/ip.json HTTP/1.1\n```\n\n#### Prompts\n\nPrompts are values inputed by the user when the request runs.\n\n- Prompts referenced in `request.http` must be defined in `request.prompts`\n- Prompts defined in `request.prompts` must also be referenced in `request.http`\n\nOtherwise this will cause validation errors.\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\nname: Prompts Example\nenvs: []\n---\n\n---\nid: example\nprompts:\n  token: !!str\nhttp: |+\n  GET https://example.com HTTP/1.1\n  Authorization: Bearer {{? token}}\n\n\n```\n\n#### References\n\nIn addition to variables, secrets and prompts request templating also provides *references*: `{{@ path.to.ref}}` References are values not provided by the user but to them. See [Auth](#auth) below for an example.\n\n#### Auth\n\nAuthentication (e.g. OAuth2, Basic Auth) defines how a request sends it's credentials if any are sent. Currently the only auth type supported is `oauth2` and the only grant type supported is `client`.\n\nThe access token is available through a template reference `{{@ auth.token}}`.\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\nname: Auth example\nenvs: []\n---\n# Secrets\nclientSecret!:\n\n# Variables\nbaseUrl: https://example.com\naccessTokenUri: https://example.com/v1/token\nclientId: exampleClientKey\n---\nid: get-item-by-id\nauth:\n  type: oauth2\n  grant: client\n  accessTokenUri: \"{{$ accessTokenUri}}\"\n  clientId: \"{{$ clientId}}\"\n  clientSecret: \"{{! clientSecret}}\"\n  scopes: profile\nprompts:\n  itemId:\n    default: 123456\nhttp: |+\n  GET {{$ baseUrl}}/items/{{? itemId}} HTTP/1.1\n  accept: application/json\n  authorization: Bearer {{@ auth.token}}\n```\n\n#### Templating\n\nTemplating allows variables, secrets, prompts to be used in `request.http`: `{{$ varName}}`, `{{! secretName}}`, `{{? promptName}}`, `{{@ refs}}`\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\nname: Templating Example\nenvs: []\n---\nbaseUrl: http://example.com/\n---\nid: ip\nhttp: |+\n  GET {{$ baseUrl}} HTTP/1.1\n\n\n```\n\n#### Tests\n\nTests are expected HTTP response message strings. Actual assertion logic for tests needs to be defined. The reference implementation will check protocol version, status code, status message and body for equality. Headers that are defined in the test are tested. Headers in the actual response not found in the test are ignored.\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\nname: Testing Example\nenvs: []\n---\nbaseUrl: http://example.com/\n---\nid: ip\nhttp: |+\n  GET {{$ baseUrl}} HTTP/1.1\n\ntests:\n  shouldBeOk: |+\n    HTTP/1.1 200 OK\n\n\n```\n\n### Why YAML\n\nYAML has a number of key features that aligned with the goals of the spec.\n\n#### Multi Document Files\n\nHaving the multiple document format allows for flatter structure and syntax. Less indentation should make it easier to write and less prone to syntax errors.\n\n#### Multiline String Support\n\nWriting HTTP request and response message strings is at the core of this idea. While other formats support multiline strings they were combersome for writing HTTP message strings. Using YAML's `|+` this becomes much easier depspite other tradeoffs YAML has.\n\n## Implementations?\n\nThe focus is on a format that could and will have implementations written in many languages.\n\nThere is also a [reference implementation](IMPLEMENTATIONS.md) written in javascript to help test the spec as it's developed.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftestingrequired%2Frestfile","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftestingrequired%2Frestfile","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftestingrequired%2Frestfile/lists"}