1. Introduction
RESTspec defines a standard structure for describing HTTP API routes in a declarative, language-agnostic way. A RESTspec definition captures the methods, paths, inputs, and outputs of an API as a single structured object. This object can then be consumed by server frameworks, client generators, documentation tools, or validation layers.
The specification is deliberately minimal. It does not prescribe a transport, serialization format, or validation library. Instead, it defines the shape of a route contract and the rules that conforming implementations must follow.
Goals
- A single source of truth for API shape shared between server and client.
- Language-level type safety derived from route definitions (e.g. TypeScript, Go structs, Rust types).
- Optional runtime validation when a schema library (Zod, Ajv, Valibot, etc.) is used.
- Portability across server frameworks (Express, Hono, Fastify, etc.) and client transports (fetch, Axios, etc.).
Non-Goals
- Replacing OpenAPI or JSON Schema for public API documentation.
- Defining middleware, authentication, or authorization.
- Prescribing a specific validation library.
2. Terminology
| Term | Definition |
|---|---|
| Route Schema | The top-level object describing all routes in an API. Organized by method, then by path. |
| Route Entry | A single route definition at a given method + path combination. Contains fields for payload, query parameters, and response. |
| Path Template | A URL path containing zero or more colon-prefixed parameters (e.g. /users/:id). |
| Payload | The request body. Only applicable to methods that carry a body (POST, PUT, PATCH, DELETE, and custom methods). |
| Query Params | Key-value parameters appended to the URL query string. |
| Response | The expected shape of a successful response body. |
| Server Binding | An implementation that reads a Route Schema and registers handlers on a server framework. |
| Client Binding | An implementation that reads a Route Schema and provides a typed interface for making HTTP requests. |
| Schema Object | A runtime validation object (e.g. Zod schema) that can both describe and validate a type. Optional — when absent, type safety is compile-time only. |
3. Route Schema
A Route Schema is a structured object with the following shape:
{
METHOD: {
"PATH_TEMPLATE": RouteEntry,
"PATH_TEMPLATE": RouteEntry,
...
},
...
}
The first level keys are HTTP methods. The second level keys are path templates. Each value is a Route Entry.
3.1 Route Entry
A Route Entry describes a single endpoint. It contains the following fields:
| Field | Required | Availability | Description |
|---|---|---|---|
response |
required | All methods | The shape of the response body. Can be a schema object or a static type declaration. |
payload |
optional | POST, PUT, PATCH, DELETE, custom methods | The shape of the request body. MUST NOT appear on GET entries. |
queryParams |
optional | All methods | The shape of the URL query parameters. |
3.2 Type Representations
Each field in a Route Entry can be expressed in one of two ways, depending on the implementation:
Schema Objects (runtime)
A runtime validation object that can parse and validate data. Enables both compile-time type inference and runtime validation.
// Example: Zod
{
response: z.object({
id: z.string(),
name: z.string(),
})
}
Static Types (compile-time)
A language-level type declaration. Provides compile-time type safety with zero runtime cost. No validation occurs.
// Example: TypeScript type
{
response: {
id: string
name: string
}
}
3.3 Full Example
{
GET: {
"/users": {
queryParams: { page: number, limit: number },
response: { items: User[], total: number }
},
"/users/:id": {
response: { id: string, name: string, email: string }
}
},
POST: {
"/users": {
payload: { name: string, email: string },
response: { id: string }
}
},
DELETE: {
"/users/:id": {
response: void
}
}
}
4. HTTP Methods
RESTspec defines the following standard methods. Implementations MAY support additional custom methods.
| Method | Has Payload | Description |
|---|---|---|
| GET | No | Retrieve a resource. MUST NOT include a payload field. |
| POST | Yes | Create a resource or trigger an action. |
| PUT | Yes | Replace a resource entirely. |
| PATCH | Yes | Partially update a resource. |
| DELETE | Yes | Remove a resource. Payload is optional but permitted. |
4.1 Custom Methods
Implementations MAY support custom HTTP methods (e.g. QUERY) as top-level keys in the Route Schema. Custom methods follow the same Route Entry structure as standard methods and carry a payload by default.
When a server binding encounters a custom method, it SHOULD register a catch-all handler for the path and
reject requests whose HTTP method does not match. The RECOMMENDED rejection status is
405 Method Not Allowed.
5. Path Parameters
Path parameters are defined using colon-prefixed segments within path templates.
5.1 Syntax
A parameter segment begins with : followed by an identifier: /resource/:paramName.
Multiple parameters may appear in a single path.
| Path Template | Extracted Parameters |
|---|---|
/users/:id |
{ id: string } |
/orgs/:orgId/members/:memberId |
{ orgId: string, memberId: string } |
/health |
(none) |
5.2 Rules
- All path parameter values are strings. Type coercion is the responsibility of the handler.
- Parameter names MUST be valid identifiers (alphanumeric and underscores).
- A path MUST NOT contain duplicate parameter names.
5.3 Substitution
Client bindings MUST replace each :param segment with the corresponding value before making a
request.
If a required parameter is missing, the client MUST throw an error.
// Template: /orgs/:orgId/members/:memberId
// Params: { orgId: "acme", memberId: "42" }
// Result: /orgs/acme/members/42
5.4 Server Access
Server bindings MUST expose path parameter values to handlers. The mechanism is framework-specific
(e.g. req.params in Express, c.req.param() in Hono).
6. Request Format
A conforming client MUST construct requests as follows:
6.1 URL Construction
- Start with the base URL.
- Append the path template after substituting all path parameters.
- If
queryParamsare provided, serialize them as a URL query string and append.
6.2 Body Serialization
- The default content type is
application/json. - The
payloadfield is serialized as JSON in the request body. - GET requests MUST NOT include a request body.
6.3 Headers
Implementations SHOULD provide a mechanism for injecting custom headers (e.g. authorization tokens) into every request. The header provider MAY be synchronous or asynchronous.
7. Response Format
7.1 Success Responses
- A successful response has an HTTP status in the
2xxrange. - The response body is parsed as JSON and MUST conform to the
responsefield of the Route Entry.
7.2 Void Responses
When the response type is void (or equivalent), the client SHOULD NOT attempt
to parse the response body and SHOULD return undefined (or the language equivalent).
7.3 Error Responses
A response with a non-2xx status code is considered an error. The client SHOULD attempt
to parse the error body as JSON and surface the error message.
8. Known Implementations
| Library | Language | Server | Client |
|---|---|---|---|
@jokio/rpc |
TypeScript | Express | fetch |