Skip to content

Commit 58b65fb

Browse files
authored
Merge pull request #1037 from BitGo/codehike
feat(docs): Add core @api-ts/io-ts-http docs to Docusaurus
2 parents 8c756ef + 3e6d373 commit 58b65fb

File tree

12 files changed

+511
-9
lines changed

12 files changed

+511
-9
lines changed

website/docs/reference/_category_.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"label": "Reference",
3-
"position": 4,
3+
"position": 5,
44
"link": {
55
"type": "generated-index",
66
"description": "Technical specifications and API reference documentation"
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
sidebar_position: 2
3+
---
4+
5+
# `apiSpec`
6+
7+
### Overview
8+
9+
A helper function that defines a collection of HTTP routes, associating them with
10+
operation names to represent a service's complete API contract. Primarily serves as a
11+
typed container for `httpRoute` definitions.
12+
13+
### Specification
14+
15+
Accepts a single argument: an object where keys represent operation names (e.g.,
16+
`'api.v1.user'`) and values are objects that map HTTP methods (lowercase strings like
17+
`'get'`, `'post'`) to corresponding `httpRoute` definitions.
18+
19+
### Metadata
20+
21+
`@version`: A JSDoc tag added to the exported `apiSpec` variable declaration that will
22+
be used as the API `version` property when generating artifacts like OpenAPI schemas.
23+
24+
### Usage Example
25+
26+
```typescript
27+
import { apiSpec } from '@api-ts/io-ts-http';
28+
import * as t from 'io-ts'; // Assuming base io-ts types are needed elsewhere
29+
import { httpRoute, httpRequest } from '@api-ts/io-ts-http'; // Assuming httpRoute/Request defined here or imported
30+
31+
// Assume GetUser, CreateUser etc. are pre-defined httpRoute objects
32+
import { GetUser, CreateUser, UpdateUser, DeleteUser, PatchUser } from './routes/user';
33+
import { GetMessage, CreateMessage } from './routes/message';
34+
35+
/**
36+
* Example service API definition.
37+
* @version 1.0.0
38+
*/
39+
export const API = apiSpec({
40+
'api.v1.message': {
41+
get: GetMessage,
42+
post: CreateMessage,
43+
},
44+
'api.v1.user': {
45+
get: GetUser,
46+
post: CreateUser,
47+
put: UpdateUser,
48+
delete: DeleteUser,
49+
patch: PatchUser,
50+
},
51+
});
52+
```
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"label": "Combinators",
3+
"position": 5,
4+
"link": {
5+
"type": "generated-index",
6+
"description": "Technical specifications and API reference documentation"
7+
}
8+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# `flattened`
2+
3+
### Overview
4+
5+
The `flattened` combinator creates a codec that decodes a nested structure into a flat
6+
object back into a nested structure.
7+
8+
### Specification
9+
10+
Accepts two arguments:
11+
12+
- `name`: (`string`) A name for the codec, used in error messages.
13+
- `nestedProps`: (`object`) An object that defines the encoded nested structure. Each
14+
key represents a top-level property in the encoded form, and its value is an object
15+
that maps the nested keys to their `io-ts` codecs.
16+
17+
Returns a new codec.
18+
19+
### Behavior
20+
21+
- Decoding: Takes the nested input (matching the `nestedProps` structure) and outputs a
22+
flat object that contains all the inner properties.
23+
- Encoding: Takes the flat object (containing keys from the inner structures) and
24+
outputs the nested structure defined by `nestedProps`.
25+
26+
### Caveats
27+
28+
- Defining multiple nested properties with the same name across different top-level keys
29+
can lead to undefined behavior. The library tries to prevent this where statically.
30+
31+
### Usage Example
32+
33+
```typescript
34+
import * as t from 'io-ts';
35+
import { flattened } from '@api-ts/io-ts-http';
36+
37+
const FlatCodec = flattened('FlatCodec', {
38+
metadata: {
39+
// Top-level key in encoded form
40+
id: t.string,
41+
createdAt: t.string, // Assume DateFromString etc. if needed
42+
},
43+
payload: {
44+
// Another top-level key in encoded form
45+
value: t.number,
46+
},
47+
});
48+
49+
// Decoded type:
50+
// type Decoded = {
51+
// id: string;
52+
// createdAt: string;
53+
// value: number;
54+
// };
55+
56+
// Encoded type (Input for decode, Output for encode):
57+
// type Encoded = {
58+
// metadata: {
59+
// id: string;
60+
// createdAt: string;
61+
// };
62+
// payload: {
63+
// value: number;
64+
// };
65+
// };
66+
```
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
sidebar_position: 5
3+
---
4+
5+
# Combinators
6+
7+
Helper functions that construct `io-ts` codecs, often used within `httpRequest`
8+
definitions.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# `optional`
2+
3+
### Overview
4+
5+
`optional` creates a codec that represents a value of a specified type or `undefined`.
6+
This is useful for marking properties as optional when used with `optionalize`.
7+
8+
### Specification
9+
10+
Accepts one argument:
11+
12+
- `codec`: (`io-ts` Codec) The base codec for the type.
13+
14+
Returns a new codec that represents `t.union([codec, t.undefined])`.
15+
16+
### Usage Example
17+
18+
```typescript
19+
import * as t from 'io-ts';
20+
import { optional } from '@api-ts/io-ts-http';
21+
22+
// Represents: string | undefined
23+
const MaybeString = optional(t.string);
24+
```
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# `optionalize`
2+
3+
### Overview
4+
5+
`optionalize` creates a codec for an object type where properties whose codecs can
6+
resolve to `undefined` (typically created using `optional` or
7+
`t.union([..., t.undefined])`) are marked as optional (`?`) in the resulting TypeScript
8+
type.
9+
10+
### Specification
11+
12+
Accepts one argument:
13+
14+
- `props`: (`object`) An object that maps property names to `io-ts` codecs, similar to
15+
`t.type` or `t.partial`.
16+
17+
Returns a new object codec. The codec effectively combines `t.type` (for required
18+
properties) and `t.partial` (for properties whose codecs include `t.undefined`).
19+
20+
### Usage Example
21+
22+
```typescript
23+
import * as t from 'io-ts';
24+
import { optional, optionalize } from '@api-ts/io-ts-http';
25+
26+
const ItemCodec = optionalize({
27+
requiredId: t.string,
28+
optionalValue: optional(t.number), // Uses optional combinator
29+
maybeDefined: t.union([t.string, t.undefined]), // Also becomes optional
30+
});
31+
32+
// Resulting type:
33+
// type Item = {
34+
// requiredId: string;
35+
// optionalValue?: number;
36+
// maybeDefined?: string;
37+
// }
38+
```
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
---
2+
sidebar_position: 4
3+
---
4+
5+
# `httpRequest`
6+
7+
### Overview
8+
9+
`httpRequest` is a helper function that builds `io-ts` codecs specifically for HTTP
10+
requests. It defines the expected structure of path parameters, query parameters,
11+
headers, and the request body. The resulting codec flattens these distinct parts into a
12+
single object upon successful decoding.
13+
14+
### Specification
15+
16+
Accepts a single optional argument: an object that can contain the following optional
17+
properties:
18+
19+
- `params`: (`object`) An object that maps path parameter names (strings matching
20+
`{name}` syntax in `httpRoute` path) to `io-ts` codecs for validation and type
21+
conversion.
22+
- `query`: (`object`) An object that maps query parameter names (strings) to `io-ts`
23+
codecs.
24+
- `headers`: (`object`) An object that maps HTTP header names (lowercase strings) to
25+
`io-ts` codecs.
26+
- `body`: (`object` | `io-ts` Codec) An object that maps field names within the request
27+
body to `io-ts` codecs. Assumes an object structure by default. (See Limitations).
28+
29+
The function returns an `io-ts` codec.
30+
31+
### Behavior
32+
33+
- Decoding: Takes an input object that conforms to `GenericHttpRequest` (see below).
34+
Validates and parses the `params`, `query`, `headers`, and `body` based on the
35+
provided codecs. If successful, returns a flattened object that contains all decoded
36+
properties directly.
37+
- Encoding: Takes a flattened object (matching the decoded type). Encodes the properties
38+
back into the structured `GenericHttpRequest` format, suitable for sending as a
39+
request.
40+
41+
### Decoded Type Structure
42+
43+
The `t.TypeOf` of the resulting codec is a flat object that contains properties from
44+
`params`, `query`, `headers`, and `body` combined.
45+
46+
```typescript
47+
import * as t from 'io-ts';
48+
import { httpRequest } from '@api-ts/io-ts-http';
49+
import { NumberFromString, DateFromISOString } from 'io-ts-types'; // Example types
50+
51+
const ExampleRequestCodec = httpRequest({
52+
params: {
53+
id: NumberFromString, // from path '/.../{id}'
54+
},
55+
query: {
56+
filter: t.string, // from query '?filter=...'
57+
},
58+
body: {
59+
content: t.string,
60+
timestamp: DateFromISOString,
61+
},
62+
});
63+
64+
// The resulting decoded type:
65+
type ExampleDecoded = t.TypeOf<typeof ExampleRequestCodec>;
66+
// Equivalent to:
67+
// type ExampleDecoded = {
68+
// id: number; // from params
69+
// filter: string; // from query
70+
// content: string; // from body
71+
// timestamp: Date; // from body
72+
// };
73+
```
74+
75+
### Limitations
76+
77+
Assumes the request `body`, if present and defined via the shorthand object syntax, is
78+
an object whose properties can be flattened. For non-object bodies, see the advanced
79+
usage notes under `httpRoute`.
80+
81+
### Usage Examples
82+
83+
- Query Parameters Only:
84+
85+
```typescript
86+
const RequestWithQuery = httpRequest({
87+
query: { message: t.string, count: NumberFromString },
88+
});
89+
// Decoded type: { message: string; count: number }
90+
```
91+
92+
- Path and body parameters:
93+
94+
```typescript
95+
const RequestWithPathAndBody = httpRequest({
96+
params: { userId: t.string },
97+
body: { data: t.unknown },
98+
});
99+
// Decoded type: { userId: string; data: unknown }
100+
```

0 commit comments

Comments
 (0)