Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion website/docs/reference/_category_.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"label": "Reference",
"position": 4,
"position": 5,
"link": {
"type": "generated-index",
"description": "Technical specifications and API reference documentation"
Expand Down
52 changes: 52 additions & 0 deletions website/docs/reference/io-ts-http/apispec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
sidebar_position: 2
---

# `apiSpec`

### Overview

A helper function that defines a collection of HTTP routes, associating them with
operation names to represent a service's complete API contract. Primarily serves as a
typed container for `httpRoute` definitions.

### Specification

Accepts a single argument: an object where keys represent operation names (e.g.,
`'api.v1.user'`) and values are objects that map HTTP methods (lowercase strings like
`'get'`, `'post'`) to corresponding `httpRoute` definitions.

### Metadata

`@version`: A JSDoc tag added to the exported `apiSpec` variable declaration that will
be used as the API `version` property when generating artifacts like OpenAPI schemas.

### Usage Example

```typescript
import { apiSpec } from '@api-ts/io-ts-http';
import * as t from 'io-ts'; // Assuming base io-ts types are needed elsewhere
import { httpRoute, httpRequest } from '@api-ts/io-ts-http'; // Assuming httpRoute/Request defined here or imported

// Assume GetUser, CreateUser etc. are pre-defined httpRoute objects
import { GetUser, CreateUser, UpdateUser, DeleteUser, PatchUser } from './routes/user';
import { GetMessage, CreateMessage } from './routes/message';

/**
* Example service API definition.
* @version 1.0.0
*/
export const API = apiSpec({
'api.v1.message': {
get: GetMessage,
post: CreateMessage,
},
'api.v1.user': {
get: GetUser,
post: CreateUser,
put: UpdateUser,
delete: DeleteUser,
patch: PatchUser,
},
});
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"label": "Combinators",
"position": 5,
"link": {
"type": "generated-index",
"description": "Technical specifications and API reference documentation"
}
}
66 changes: 66 additions & 0 deletions website/docs/reference/io-ts-http/combinators/flattened.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# `flattened`

### Overview

The `flattened` combinator creates a codec that decodes a nested structure into a flat
object back into a nested structure.

### Specification

Accepts two arguments:

- `name`: (`string`) A name for the codec, used in error messages.
- `nestedProps`: (`object`) An object that defines the encoded nested structure. Each
key represents a top-level property in the encoded form, and its value is an object
that maps the nested keys to their `io-ts` codecs.

Returns a new codec.

### Behavior

- Decoding: Takes the nested input (matching the `nestedProps` structure) and outputs a
flat object that contains all the inner properties.
- Encoding: Takes the flat object (containing keys from the inner structures) and
outputs the nested structure defined by `nestedProps`.

### Caveats

- Defining multiple nested properties with the same name across different top-level keys
can lead to undefined behavior. The library tries to prevent this where statically.

### Usage Example

```typescript
import * as t from 'io-ts';
import { flattened } from '@api-ts/io-ts-http';

const FlatCodec = flattened('FlatCodec', {
metadata: {
// Top-level key in encoded form
id: t.string,
createdAt: t.string, // Assume DateFromString etc. if needed
},
payload: {
// Another top-level key in encoded form
value: t.number,
},
});

// Decoded type:
// type Decoded = {
// id: string;
// createdAt: string;
// value: number;
// };

// Encoded type (Input for decode, Output for encode):
// type Encoded = {
// metadata: {
// id: string;
// createdAt: string;
// };
// payload: {
// value: number;
// };
// };
```
8 changes: 8 additions & 0 deletions website/docs/reference/io-ts-http/combinators/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
sidebar_position: 5
---

# Combinators

Helper functions that construct `io-ts` codecs, often used within `httpRequest`
definitions.
24 changes: 24 additions & 0 deletions website/docs/reference/io-ts-http/combinators/optional.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# `optional`

### Overview

`optional` creates a codec that represents a value of a specified type or `undefined`.
This is useful for marking properties as optional when used with `optionalize`.

### Specification

Accepts one argument:

- `codec`: (`io-ts` Codec) The base codec for the type.

Returns a new codec that represents `t.union([codec, t.undefined])`.

### Usage Example

```typescript
import * as t from 'io-ts';
import { optional } from '@api-ts/io-ts-http';

// Represents: string | undefined
const MaybeString = optional(t.string);
```
38 changes: 38 additions & 0 deletions website/docs/reference/io-ts-http/combinators/optionalize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# `optionalize`

### Overview

`optionalize` creates a codec for an object type where properties whose codecs can
resolve to `undefined` (typically created using `optional` or
`t.union([..., t.undefined])`) are marked as optional (`?`) in the resulting TypeScript
type.

### Specification

Accepts one argument:

- `props`: (`object`) An object that maps property names to `io-ts` codecs, similar to
`t.type` or `t.partial`.

Returns a new object codec. The codec effectively combines `t.type` (for required
properties) and `t.partial` (for properties whose codecs include `t.undefined`).

### Usage Example

```typescript
import * as t from 'io-ts';
import { optional, optionalize } from '@api-ts/io-ts-http';

const ItemCodec = optionalize({
requiredId: t.string,
optionalValue: optional(t.number), // Uses optional combinator
maybeDefined: t.union([t.string, t.undefined]), // Also becomes optional
});

// Resulting type:
// type Item = {
// requiredId: string;
// optionalValue?: number;
// maybeDefined?: string;
// }
```
100 changes: 100 additions & 0 deletions website/docs/reference/io-ts-http/httpRequest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
sidebar_position: 4
---

# `httpRequest`

### Overview

`httpRequest` is a helper function that builds `io-ts` codecs specifically for HTTP
requests. It defines the expected structure of path parameters, query parameters,
headers, and the request body. The resulting codec flattens these distinct parts into a
single object upon successful decoding.

### Specification

Accepts a single optional argument: an object that can contain the following optional
properties:

- `params`: (`object`) An object that maps path parameter names (strings matching
`{name}` syntax in `httpRoute` path) to `io-ts` codecs for validation and type
conversion.
- `query`: (`object`) An object that maps query parameter names (strings) to `io-ts`
codecs.
- `headers`: (`object`) An object that maps HTTP header names (lowercase strings) to
`io-ts` codecs.
- `body`: (`object` | `io-ts` Codec) An object that maps field names within the request
body to `io-ts` codecs. Assumes an object structure by default. (See Limitations).

The function returns an `io-ts` codec.

### Behavior

- Decoding: Takes an input object that conforms to `GenericHttpRequest` (see below).
Validates and parses the `params`, `query`, `headers`, and `body` based on the
provided codecs. If successful, returns a flattened object that contains all decoded
properties directly.
- Encoding: Takes a flattened object (matching the decoded type). Encodes the properties
back into the structured `GenericHttpRequest` format, suitable for sending as a
request.

### Decoded Type Structure

The `t.TypeOf` of the resulting codec is a flat object that contains properties from
`params`, `query`, `headers`, and `body` combined.

```typescript
import * as t from 'io-ts';
import { httpRequest } from '@api-ts/io-ts-http';
import { NumberFromString, DateFromISOString } from 'io-ts-types'; // Example types

const ExampleRequestCodec = httpRequest({
params: {
id: NumberFromString, // from path '/.../{id}'
},
query: {
filter: t.string, // from query '?filter=...'
},
body: {
content: t.string,
timestamp: DateFromISOString,
},
});

// The resulting decoded type:
type ExampleDecoded = t.TypeOf<typeof ExampleRequestCodec>;
// Equivalent to:
// type ExampleDecoded = {
// id: number; // from params
// filter: string; // from query
// content: string; // from body
// timestamp: Date; // from body
// };
```

### Limitations

Assumes the request `body`, if present and defined via the shorthand object syntax, is
an object whose properties can be flattened. For non-object bodies, see the advanced
usage notes under `httpRoute`.

### Usage Examples

- Query Parameters Only:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Query Parameters Only:
- Query parameters only:

This doesn't seem like it needs to be in title case.


```typescript
const RequestWithQuery = httpRequest({
query: { message: t.string, count: NumberFromString },
});
// Decoded type: { message: string; count: number }
```

- Path and body parameters:

```typescript
const RequestWithPathAndBody = httpRequest({
params: { userId: t.string },
body: { data: t.unknown },
});
// Decoded type: { userId: string; data: unknown }
```
Loading
Loading