# HTTP Contracts

> HTTP Contracts at the Askr server boundary, with validated input and explicit failure states.

Source: [https://askrjs.com/docs/http-contracts](https://askrjs.com/docs/http-contracts)

Status: stable. Packages: @askrjs/fetch, @askrjs/schema, @askrjs/server/openapi.

**Published packages are authoritative.** Examples may lag behind a published contract. When guidance differs, verify the exports and TypeScript declarations in your installed package, then file an issue.

## Example

Define an executable schema once and reuse its JSON Schema representation in the HTTP contract and generated-client workflow.

```tsx
import { schema } from '@askrjs/schema';

export const projectInput = schema.object({
  name: schema.string({ minLength: 1 }),
  ownerId: schema.uuid(),
});

const parsed = projectInput.safeParse(await request.json());
const jsonSchema = projectInput.jsonSchema;
```

## Endpoint descriptors

get(), post(), put(), patch(), del(), head(), and options() from @askrjs/fetch each return an EndpointBuilder you chain .params&lt;T&gt;(), .query&lt;T&gt;(), .headers&lt;T&gt;(), .body(codec), .returns(status, codec), and .errors({...}) on to describe one HTTP operation. defineApi({...}, metadata?) collects a map of these builders into an ApiDefinition that both the client and the server side of the contract can share. Paths use OpenAPI-style {name} parameters — colon params and wildcards are rejected, and a declared parameter name must exactly match one in the path.

## Typed client boundary

createClient(api, { baseUrl, ... }) turns an ApiDefinition into an object whose methods mirror the keys you passed to defineApi(), each one typed from that endpoint's params, query, headers, and body plus its registered response and error codecs. Call inputs and outputs come straight from the descriptor, so nothing about fetch, headers, or serialization needs to leak into calling code. The same descriptors also drive createFetch() for one-off calls that don't need a full client.

## Schemas

@askrjs/schema builds executable schemas — schema.object(), schema.string(), schema.array(), and so on — that double as runtime validators and OpenAPI documentation. Any object with a safeParse(value) method satisfies the Validator contract that @askrjs/fetch's codecs and parameter specs expect, so you aren't locked into @askrjs/schema specifically to validate params, query values, headers, or bodies.

## OpenAPI artifacts

@askrjs/server/openapi's createApi() attaches request and response schemas to routes as you register them, and api.toOpenApiDocument() produces a deterministic, deeply frozen OpenAPI 3.1.2 document from that registration. The askr CLI's askr openapi command writes that document to YAML on disk, and askr openapi --check compares it byte-for-byte without writing, which makes it a clean CI gate against undocumented drift.

## Documentation navigation

[Previous](https://askrjs.com/docs/authentication/framework-routes/index.md) | [Next](https://askrjs.com/docs/http-contracts/typed-clients/index.md)
