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
32 changes: 31 additions & 1 deletion docs/protocols/http_client.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ HTTP client generator creates type-safe functions for making HTTP requests based

It is currently available through the generators ([channels](../generators/channels.md)):

All of this is available through [AsyncAPI](../inputs/asyncapi.md). [Requires HTTP `method` binding for operation and `statusCode` for messages](../inputs/asyncapi.md#http-client).
This is available through [AsyncAPI](../inputs/asyncapi.md) ([requires the HTTP `method` binding for operations and `statusCode` for messages](../inputs/asyncapi.md#http-client)) and directly from [OpenAPI](../inputs/openapi.md) documents (see [From OpenAPI](#from-openapi) below).

## TypeScript

Expand Down Expand Up @@ -132,6 +132,36 @@ console.log(response.rawData); // Raw JSON response
</tbody>
</table>

### From OpenAPI

The `http_client` protocol is also generated directly from an OpenAPI document (2.0/3.0/3.1). Each path + method becomes one function. Configure the `channels` generator with `inputType: 'openapi'` and `protocols: ['http_client']`.

Function names come from each operation's `operationId` (camel-cased). When an operation has **no** `operationId`, a name is synthesized from the method and path, e.g. `GET /v2/connect/{referenceId}` → `getV2ConnectReferenceId`. Give your operations `operationId`s for the cleanest client.

As a consumer you work with three generated pieces: the **call functions** (`http_client.ts`), the **request/response body models** (`payload/`), and the **path/query parameter models** (`parameter/`):

```ts
import { http_client } from './__gen__/channels';
import { PostV2ConnectRequest } from './__gen__/channels/payload/PostV2ConnectRequest';
import { GetV2ConnectReferenceIdParameters } from './__gen__/channels/parameter/GetV2ConnectReferenceIdParameters';

// Request with a body: build the model, pass it as `payload`.
const created = await http_client.postV2Connect({
server: 'https://api.example.com',
payload: new PostV2ConnectRequest({ returnUrl: 'https://shop.example/return' })
});
console.log(created.data.connectUrl); // typed response model

// Request with a path parameter: supply it through the parameter model.
const connect = await http_client.getV2ConnectReferenceId({
server: 'https://api.example.com',
parameters: new GetV2ConnectReferenceIdParameters({ referenceId: 'ref_123' })
});
console.log(connect.data.safepayAccountId);
```

See the runnable [`openapi-http-client` example](https://github.com/the-codegen-project/cli/tree/main/examples/openapi-http-client) for a complete, self-contained setup.

## Authentication

The HTTP client uses a discriminated union for authentication, providing excellent TypeScript autocomplete support.
Expand Down
3 changes: 3 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ An example demonstrating how to generate complete, type-safe client SDKs for NAT
### [E-commerce AsyncAPI Types](./ecommerce-asyncapi-types/)
A comprehensive example showing how to generate TypeScript types from AsyncAPI specifications for an e-commerce messaging system.

### [OpenAPI HTTP Client](./openapi-http-client/)
A minimal, self-contained example of generating a type-safe HTTP client from an OpenAPI document — and how to consume it: building request bodies, supplying path parameters, and reading typed responses.

## Getting Started

1. Choose an example that matches your use case
Expand Down
62 changes: 62 additions & 0 deletions examples/openapi-http-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# OpenAPI HTTP Client

A minimal, self-contained example of generating a **type-safe HTTP client** from an OpenAPI document with the `channels` generator and the `http_client` protocol — and, importantly, how to *consume* it as an API client.

**Files:**
- `safepay-nordic-sample.json` — a trimmed OpenAPI 3.1 document (a payments-style API). None of its operations declare an `operationId`, so this also demonstrates how function names are synthesized.
- `codegen.config.js` — configuration selecting the `channels` generator with the `http_client` protocol.
- `src/index.ts` — a runnable demo consuming the generated client.
- `src/generated` — the generated output (committed so you can browse it without running anything).

## Usage

```bash
npm install
npm run generate # regenerate src/generated from the OpenAPI document
npm run demo # run the consumer demo (set SAFEPAY_SERVER to hit a real server)
```

## What gets generated, and what you actually use

The generator emits a few folders. As a **consumer** you mostly care about one file, and touch the others only through it:

| Folder / file | What it is | You use it to… |
|---|---|---|
| `generated/http_client.ts` | **The call functions** — one per operation, plus the shared auth/pagination/retry machinery (private). Only the operation functions are exported. | This is your entry point. Import functions from here. |
| `generated/payload/` | Request & response **body** models with `marshal()`/`unmarshal()`. | Build request bodies; read strongly-typed responses off `response.data`. |
| `generated/parameter/` | Path & query **parameter** models. | Supply path/query parameters to operations that need them. |
| `generated/index.ts` | Re-exports the protocol namespace (`http_client`). | `import {http_client} from './generated'`. |

You rarely call `marshal()`/`unmarshal()` yourself — the client does it. You construct a request-body model, pass it as `payload`, and read the typed result from `response.data`.

## The three moving parts (see `src/index.ts`)

```ts
import {http_client} from './generated';
import {PostV2ConnectRequest} from './generated/payload/PostV2ConnectRequest';
import {GetV2ConnectReferenceIdParameters} from './generated/parameter/GetV2ConnectReferenceIdParameters';

// Body: build it with the generated request model, pass as `payload`.
const body = new PostV2ConnectRequest({returnUrl: 'https://shop.example/return'});
const created = await http_client.postV2Connect({server, payload: body});
created.data.connectUrl; // typed

// Path parameters: supply them through the generated parameter model.
const params = new GetV2ConnectReferenceIdParameters({referenceId: 'ref_123'});
const connect = await http_client.getV2ConnectReferenceId({server, parameters: params});
connect.data.safepayAccountId; // typed
```

Every function returns `HttpClientResponse<T>` where `data` is the unmarshalled, typed response model, alongside `status`, `headers`, and pagination helpers.

## About the generated function names

The operations in this document have **no `operationId`**, so names are synthesized from the HTTP method and the path, preserving word boundaries:

| Operation | Generated function |
|---|---|
| `POST /v2/connect` | `postV2Connect` |
| `GET /v2/connect/{referenceId}` | `getV2ConnectReferenceId` |
| `GET /v2/users/{safepayAccountId}/bank-accounts` | `getV2UsersSafepayAccountIdBankAccounts` |

If your document declares `operationId`s, those are used verbatim (camel-cased) instead — which is almost always what you want. Give your operations meaningful `operationId`s for the cleanest client.
12 changes: 12 additions & 0 deletions examples/openapi-http-client/codegen.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default {
inputType: 'openapi',
inputPath: './safepay-nordic-sample.json',
generators: [
{
preset: 'channels',
outputPath: './src/generated',
language: 'typescript',
protocols: ['http_client']
}
]
};
Loading
Loading