Skip to content

Commit 1c2b000

Browse files
docs(superagent-wrapper): Restructure documentation as Diátaxis Reference section
This commit refactors the documentation for the `@api-ts/superagent-wrapper` package, migrating technical details from the main README into a dedicated, structured Reference section following the Diátaxis framework. **Motivation:** The previous documentation, while providing a getting started guide, lacked a formal, easily navigable technical reference for the package's core components. Users needing specific details about function signatures, parameters, return types, or the structure of the generated API client had to infer them from the narrative guide and examples. Adopting the Diátaxis framework provides a standardized, clear structure for technical information, improving user experience and maintainability. **Changes Implemented:** 1. **Established Diátaxis Reference Structure:** Created a new documentation structure under `docs/reference/superagent-wrapper/` specifically for reference material. 2. **Component-Based File Organization:** Split the reference documentation into multiple MDX files, each focusing on a distinct component or concept: * `index.mdx`: Provides an overview and entry point for the `@api-ts/superagent-wrapper` reference section. * `superagent-request-factory.mdx`: Contains the detailed technical reference for the `superagentRequestFactory` function. * `supertest-request-factory.mdx`: Contains the detailed technical reference for the `supertestRequestFactory` function. * `build-api-client.mdx`: Contains the detailed technical reference for the `buildApiClient` function. * `api-client.mdx`: Provides a comprehensive description of the structure of the `ApiClient` object returned by `buildApiClient`, including its operation methods, the `PreparedRequest` methods (`.decode()`, `.decodeExpecting()`), and the structure of the `ApiResponse`/`SpecificApiResponse` objects. 3. **Content Migration and Enhancement:** Extracted technical details and examples from the original README and rewrote them into formal reference documentation. This includes: * Precise descriptions of each function's purpose. * Clear representation of function signatures (including conceptual type definitions where applicable). * Detailed breakdown of parameters and return values. * Technical explanation of the generated `ApiClient` object's structure and behavior. * Explicit documentation of the `.decode()` and `.decodeExpecting()` methods and the response objects they return, including notes on type narrowing. **Benefits (Impact on Users):** * **Improved Findability:** Users can now directly navigate to the specific component they need information about (e.g., `buildApiClient`, `.decode()`). * **Enhanced Clarity:** Provides clear, unambiguous technical descriptions separate from narrative guides. * **Better Organization:** Structured according to a well-regarded documentation framework (Diátaxis). * **Increased Detail:** Offers more explicit information on signatures, types, and the behavior of the generated client than was previously available. * **Consistency:** Aligns the documentation approach with other packages potentially using the same framework (e.g., `@api-ts/io-ts-http`). This restructuring significantly improves the quality and usability of the technical documentation for `@api-ts/superagent-wrapper`.
1 parent a0399b6 commit 1c2b000

File tree

7 files changed

+408
-1
lines changed

7 files changed

+408
-1
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# API Client Usage
2+
3+
This page describes the structure and methods of the type-safe API client object that
4+
the [`buildApiClient`](./build-api-client) function returns.
5+
6+
## `ApiClient` Object Structure
7+
8+
The `buildApiClient` function returns an object that provides a type-safe interface to
9+
interact with the API defined in the `apiSpec`.
10+
11+
**Structure:**
12+
13+
- **Top-level Keys:** Match the operation names (strings) defined as the top-level keys
14+
in the input `apiSpec`.
15+
- **Nested Keys:** Under each operation name key, the keys match the HTTP methods (e.g.,
16+
`'get'`, `'put'`) defined for that operation in the `apiSpec`.
17+
- **Method Functions:** The value associated with each HTTP method key is a function
18+
representing the API call for that specific route.
19+
20+
## Operation Method (e.g., `client[opName].method(props)`)
21+
22+
**Parameters:**
23+
24+
- `props` (Object): A single argument object. Its type is inferred from the _decoded
25+
type_ of the `request` codec associated with this specific route
26+
(`apiSpec[opName][method].request`). This object contains the combined, flattened
27+
properties expected by the route (path params, query params, headers, body properties
28+
all merged into one object). The `superagent-wrapper` handles encoding this object and
29+
placing the properties into the correct parts of the HTTP request (path, query, body,
30+
etc.) based on the `httpRequest` definition.
31+
32+
**Return Value:**
33+
34+
- `PreparedRequest`: An object containing the `.decode()` and `.decodeExpecting()`
35+
methods for executing the request and handling the response.
36+
37+
**Example Access:**
38+
39+
```typescript
40+
declare const apiClient: any; // Assume apiClient was built previously
41+
// Assuming apiClient has type ApiClient<ExampleAPI> from the README example
42+
43+
const putRequest = apiClient['api.example'].put({
44+
// Type-checked against { id: number; example: { foo: string; bar: number; } }
45+
id: 123,
46+
example: { foo: 'data', bar: 456 },
47+
});
48+
// putRequest now holds an object with .decode() and .decodeExpecting() methods
49+
```
50+
51+
## `PreparedRequest` Methods
52+
53+
You can use these methods on the object that is returned after you call an operation
54+
method (like `apiClient['op'].put(...)`) but before the request is executed.
55+
56+
### `.decode()`
57+
58+
Executes the configured HTTP request and attempts to decode the response body based on
59+
the received status code and the `response` codecs defined in the corresponding
60+
`httpRoute`.
61+
62+
**Signature:**
63+
64+
```typescript
65+
// Conceptual representation - RouteDef would be the specific route definition type
66+
type ApiResponse<RouteDef> = {
67+
status: number;
68+
body: /* Union of all possible decoded response types for RouteDef | unknown */ any;
69+
// Potentially other properties from superagent response (headers, etc.)
70+
[key: string]: any; // To represent potential superagent pass-throughs
71+
};
72+
73+
// Method signature on the PreparedRequest object
74+
// decode: () => Promise<ApiResponse</* Corresponding Route Definition */>>;
75+
decode(): Promise<ApiResponse<any>>; // Use 'any' if RouteDef is too complex to represent here
76+
```
77+
78+
**Parameters:**
79+
80+
- `expectedStatus` (`number`): The specific HTTP status code that is expected in the
81+
response. This status code must be one of the keys defined in the `response` object of
82+
the corresponding `httpRoute`.
83+
84+
**Behavior:**
85+
86+
1. Sends the HTTP request.
87+
2. Receives the HTTP response.
88+
3. Compares the received status code with expectedStatus.
89+
4. If status matches expectedStatus: Attempts to decode the response body using the
90+
io-ts codec associated with expectedStatus in the httpRoute.
91+
- If decoding succeeds, the Promise resolves with the SpecificApiResponse object.
92+
- If decoding fails, the Promise is rejected with an error.
93+
5. If status does not match expectedStatus: The Promise is rejected with an error
94+
indicating the status code mismatch.
95+
96+
**Return Value:**
97+
98+
- `Promise<SpecificApiResponse>`: A Promise that resolves with a `SpecificApiResponse`
99+
object only if the received status matches `expectedStatus` and the body is
100+
successfully decoded according to the corresponding codec. The `body` type in the
101+
resolved object is narrowed specifically to the type defined for `expectedStatus`. If
102+
the conditions are not met, the Promise rejects.
103+
104+
## Response Object Structure (`ApiResponse` / `SpecificApiResponse`)
105+
106+
This is the object type that the Promises returned from `.decode()` and
107+
`.decodeExpecting()` resolve to.
108+
109+
**Properties:**
110+
111+
- `status` (`number`): The HTTP status code received from the server.
112+
- `body` (`DecodedType | unknown`): The response body.
113+
- For `.decode()`: The type is a union of all possible types successfully decoded
114+
based on the status codes defined in the `httpRoute['response']` object. If the
115+
status code was not defined or decoding failed, it might be `unknown` or hold raw
116+
response data/error info.
117+
- For `.decodeExpecting(status)`: The type is narrowed to the specific decoded type
118+
associated with the `status` key in `httpRoute['response']`.
119+
120+
**Type Narrowing:** TypeScript can effectively narrow the type of the `body` property
121+
when using conditional checks on the `status` property, especially after using
122+
`.decode()`:
123+
124+
```typescript
125+
declare const apiClient: any; // Assume apiClient was built previously
126+
// Assuming apiClient has type ApiClient<ExampleAPI> from the README example
127+
128+
async function exampleUsage() {
129+
const response = await apiClient['api.example']
130+
.put({ id: 1, example: { foo: '', bar: 0 } })
131+
.decode();
132+
133+
if (response.status === 200) {
134+
// response.body is now typed as the decoded type for status 200 (Example)
135+
console.log(response.body.foo);
136+
} else if (response.status === 400) {
137+
// response.body is now typed as the decoded type for status 400 (GenericAPIError)
138+
console.log(response.body.message);
139+
} else {
140+
// response.body might be unknown or some other type
141+
const maybeError = response.body as any;
142+
if (maybeError?.message) {
143+
console.error('Unknown error:', maybeError.message);
144+
}
145+
}
146+
}
147+
```
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# BuildApiClient
2+
3+
The `buildApiClient` function creates a type-safe API client by combining a request
4+
factory and an API specification.
5+
6+
## Syntax
7+
8+
```typescript
9+
import { ApiSpec } from '@api-ts/io-ts-http';
10+
11+
function buildApiClient<T extends ApiSpec>(
12+
requestFactory: RequestFactory,
13+
apiSpec: T,
14+
): ApiClient<T>;
15+
16+
// Types used by buildApiClient
17+
type RequestFactory = (method: string, path: string, options?: any) => any; // Returns a superagent/supertest request
18+
19+
// ApiClient structure based on the input ApiSpec 'T'
20+
type ApiClient<T extends ApiSpec> = {
21+
[OperationName in keyof T]: {
22+
[MethodName in keyof T[OperationName]]: (
23+
props: any, // Inferred from T[OperationName][MethodName]['request']
24+
) => PreparedRequest<T[OperationName][MethodName]>;
25+
};
26+
};
27+
28+
// Response types
29+
type ApiResponse<RouteDef> = {
30+
status: number;
31+
body: any;
32+
// Additional properties from the response
33+
};
34+
35+
type SpecificApiResponse<RouteDef, Status extends number> = {
36+
status: Status;
37+
body: any;
38+
// Additional properties from the response
39+
};
40+
41+
// Object returned before executing the request
42+
type PreparedRequest<RouteDef> = {
43+
decode: () => Promise<ApiResponse<RouteDef>>;
44+
decodeExpecting: (status: number) => Promise<SpecificApiResponse<RouteDef, number>>;
45+
};
46+
```
47+
48+
## Parameters
49+
50+
- `requestFactory`: A function that creates HTTP requests.
51+
52+
- Type: `RequestFactory`
53+
- Source: Returned by `superagentRequestFactory` or `supertestRequestFactory`.
54+
55+
- `apiSpec`: An object that defines the API structure, routes, requests, and responses.
56+
- Type: `ApiSpec`
57+
- Source: Created using `@api-ts/io-ts-http`'s `apiSpec` function.
58+
59+
## Return Value
60+
61+
- A strongly-typed object representing the API client.
62+
- Type: `ApiClient<T>`
63+
- See [API Client Usage](./api-client) for details on structure and methods.
64+
65+
## Example
66+
67+
```typescript
68+
import { superagentRequestFactory, buildApiClient } from '@api-ts/superagent-wrapper';
69+
import * as superagent from 'superagent';
70+
import { apiSpec } from './my-api-spec';
71+
72+
// Create a request factory
73+
const requestFactory = superagentRequestFactory(
74+
superagent,
75+
'https://api.example.com/v1',
76+
);
77+
78+
// Build the API client
79+
const apiClient = buildApiClient(requestFactory, apiSpec);
80+
81+
// Use the client to make type-safe API calls
82+
const response = await apiClient.users.get({ id: 123 }).decode();
83+
```
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
sidebar_position: 3
3+
---
4+
5+
# Superagent-Wrapper
6+
7+
This reference describes the functions and client structure in the
8+
`@api-ts/superagent-wrapper` package. You can use this documentation to understand the
9+
parameters, return values, and behavior of each component.
10+
11+
## Components
12+
13+
- [**superagentRequestFactory**](./superagent-request-factory): This function creates a
14+
request factory using `superagent` for making HTTP requests.
15+
- [**supertestRequestFactory**](./supertest-request-factory): This function creates a
16+
request factory using `supertest` for testing HTTP servers.
17+
- [**buildApiClient**](./build-api-client): This function builds a type-safe API client
18+
from a request factory and API specification.
19+
- [**API Client Usage**](./api-client): This page describes the structure and methods of
20+
the client object returned by `buildApiClient`.
21+
22+
## Getting Started
23+
24+
```typescript
25+
// Example: Creating an API client with superagent
26+
import * as superagent from 'superagent';
27+
import { superagentRequestFactory, buildApiClient } from '@api-ts/superagent-wrapper';
28+
import { myApiSpec } from './my-api-spec';
29+
30+
// 1. Create a request factory
31+
const requestFactory = superagentRequestFactory(
32+
superagent,
33+
'https://api.example.com/v1',
34+
);
35+
36+
// 2. Build the API client
37+
const apiClient = buildApiClient(requestFactory, myApiSpec);
38+
39+
// 3. Make API calls
40+
const response = await apiClient.users.get({ id: 123 }).decode();
41+
```
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# SuperagentRequestFactory
2+
3+
The `superagentRequestFactory` function creates a request factory function for making
4+
HTTP requests. This factory works with `buildApiClient` and uses `superagent` to handle
5+
the requests.
6+
7+
## Syntax
8+
9+
```typescript
10+
import * as superagent from 'superagent';
11+
12+
// Function type returned by superagentRequestFactory
13+
type RequestFactory = (
14+
method: string,
15+
path: string,
16+
options?: { params?: any; query?: any; headers?: any; body?: any },
17+
) => superagent.SuperAgentRequest;
18+
19+
function superagentRequestFactory(
20+
agent: superagent.SuperAgentStatic | superagent.SuperAgent<any>,
21+
baseUrl: string,
22+
): RequestFactory;
23+
```
24+
25+
## Parameters
26+
27+
- `agent`: The superagent library object or a pre-configured superagent instance.
28+
29+
- Type: `superagent.SuperAgentStatic | superagent.SuperAgent<any>`
30+
- Example: `superagent` or a custom agent
31+
32+
- `baseUrl`: The base URL prepended to all request paths defined in the API
33+
specification.
34+
- Type: `string`
35+
- Example: `"http://api.example.com/v1"`
36+
37+
## Return Value
38+
39+
- A request factory function that `buildApiClient` uses to initiate HTTP requests.
40+
- Type: `RequestFactory`
41+
- Takes HTTP method, path template, and request data (params, query, headers, body).
42+
- Returns a `superagent` request object.
43+
44+
## Example
45+
46+
```typescript
47+
import * as superagent from 'superagent';
48+
import { superagentRequestFactory } from '@api-ts/superagent-wrapper';
49+
import { buildApiClient } from '@api-ts/superagent-wrapper';
50+
import { myApiSpec } from './my-api-spec';
51+
52+
// Create a request factory with the base URL
53+
const requestFactory = superagentRequestFactory(
54+
superagent,
55+
'https://api.example.com/v1',
56+
);
57+
58+
// Build the API client
59+
const apiClient = buildApiClient(requestFactory, myApiSpec);
60+
61+
// Now you can use apiClient to make HTTP requests to the API
62+
```
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# SupertestRequestFactory
2+
3+
The `supertestRequestFactory` function creates a request factory function for testing
4+
HTTP servers. This factory works with `buildApiClient` and uses `supertest` to make HTTP
5+
requests.
6+
7+
## Syntax
8+
9+
```typescript
10+
import * as supertest from 'supertest';
11+
import * as superagent from 'superagent';
12+
13+
// Function type returned by supertestRequestFactory
14+
type RequestFactory = (
15+
method: string,
16+
path: string,
17+
options?: { params?: any; query?: any; headers?: any; body?: any },
18+
) => superagent.SuperAgentRequest; // supertest uses superagent requests internally
19+
20+
function supertestRequestFactory(
21+
request: supertest.SuperTest<supertest.Test>,
22+
): RequestFactory;
23+
```
24+
25+
## Parameters
26+
27+
- `request`: The request function created by initializing `supertest` with an HTTP
28+
server or app instance.
29+
- Type: `supertest.SuperTest<supertest.Test>`
30+
- Example: `supertest(app)`
31+
32+
## Return Value
33+
34+
- A request factory function that `buildApiClient` uses to initiate HTTP requests.
35+
- Type: `RequestFactory`
36+
- Integrates with the provided `supertest` request function.
37+
38+
## Example
39+
40+
```typescript
41+
import * as supertest from 'supertest';
42+
import { supertestRequestFactory } from '@api-ts/superagent-wrapper';
43+
import { buildApiClient } from '@api-ts/superagent-wrapper';
44+
import { myApiSpec } from './my-api-spec';
45+
import express from 'express';
46+
47+
// Create an Express app
48+
const app = express();
49+
50+
// Initialize supertest with the app
51+
const request = supertest(app);
52+
53+
// Create a request factory
54+
const requestFactory = supertestRequestFactory(request);
55+
56+
// Build the API client
57+
const apiClient = buildApiClient(requestFactory, myApiSpec);
58+
59+
// Now you can use apiClient for testing your Express app
60+
```

0 commit comments

Comments
 (0)