Skip to main content

HTTP(S)

HTTP client generator creates type-safe functions for making HTTP requests based on your API specification. It supports various authentication methods, retry logic, and extensibility hooks.

It is currently available through the generators (channels):

This is available through AsyncAPI (requires the HTTP method binding for operations and statusCode for messages) and directly from OpenAPI documents (see From OpenAPI below).

TypeScript

FeatureIs supported?
Download
Upload
Retry with backoff
OAuth2 Authorization code❌ (browser-only)
OAuth2 Implicit❌ (browser-only)
OAuth2 Password
OAuth2 Client Credentials
OAuth2 Token Refresh
Username/password Authentication
Bearer Authentication
Basic Authentication
API Key Authentication
Request/Response Hooks
XML Based API
JSON Based API
POST
GET
PATCH
DELETE
PUT
HEAD
OPTIONS

Channels

Read more about the channels generator here.

Input (AsyncAPI)Using the code
asyncapi: 3.0.0
info:
title: User API
version: 1.0.0
channels:
ping:
address: /ping
messages:
pingRequest:
$ref: '#/components/messages/PingRequest'
pongResponse:
$ref: '#/components/messages/PongResponse'
operations:
postPing:
action: send
channel:
$ref: '#/channels/ping'
bindings:
http:
method: POST
reply:
channel:
$ref: '#/channels/ping'
messages:
- $ref: '#/channels/ping/messages/pongResponse'
components:
messages:
PingRequest:
payload:
type: object
properties:
message:
type: string
PongResponse:
payload:
type: object
properties:
response:
type: string
bindings:
http:
statusCode: 200
// Location depends on the payload generator configurations
import { Ping } from './__gen__/payloads/Ping';
import { Pong } from './__gen__/payloads/Pong';
// Location depends on the channel generator configurations
import { Protocols } from './__gen__/channels';
const { http_client } = Protocols;
const { postPingPostRequest } = http_client;

// Create a request payload
const pingMessage = new Ping({ message: 'Hello!' });

// Make a simple request
const response = await postPingPostRequest({
payload: pingMessage,
baseUrl: 'https://api.example.com'
});

// Access the response
console.log(response.data.response); // The deserialized Pong
console.log(response.status); // 200
console.log(response.headers); // Response headers
console.log(response.rawData); // Raw JSON response

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 operationIds 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/):

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({
baseUrl: '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({
baseUrl: 'https://api.example.com',
parameters: new GetV2ConnectReferenceIdParameters({ referenceId: 'ref_123' })
});
console.log(connect.data.safepayAccountId);

See the runnable openapi-http-client example for a complete, self-contained setup.

Authentication

The HTTP client uses a discriminated union for authentication, providing excellent TypeScript autocomplete support.

Bearer Token

const response = await postPingPostRequest({
payload: message,
baseUrl: 'https://api.example.com',
auth: {
type: 'bearer',
token: 'your-jwt-token'
}
});

Basic Authentication

const response = await postPingPostRequest({
payload: message,
baseUrl: 'https://api.example.com',
auth: {
type: 'basic',
username: 'user',
password: 'pass'
}
});

API Key

// API Key in header (default)
const response = await postPingPostRequest({
payload: message,
baseUrl: 'https://api.example.com',
auth: {
type: 'apiKey',
key: 'your-api-key',
name: 'X-API-Key', // Header name (default: 'X-API-Key')
in: 'header' // 'header' or 'query'
}
});

// API Key in query parameter
const response = await postPingPostRequest({
payload: message,
baseUrl: 'https://api.example.com',
auth: {
type: 'apiKey',
key: 'your-api-key',
name: 'api_key',
in: 'query'
}
});

OAuth2 Client Credentials

For server-to-server authentication:

const response = await postPingPostRequest({
payload: message,
baseUrl: 'https://api.example.com',
auth: {
type: 'oauth2',
flow: 'client_credentials',
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
tokenUrl: 'https://auth.example.com/oauth/token',
scopes: ['read', 'write'],
onTokenRefresh: (tokens) => {
// Called when tokens are obtained/refreshed
console.log('New access token:', tokens.accessToken);
}
}
});

OAuth2 Password Flow

For legacy applications requiring username/password:

const response = await postPingPostRequest({
payload: message,
baseUrl: 'https://api.example.com',
auth: {
type: 'oauth2',
flow: 'password',
clientId: 'your-client-id',
username: 'user@example.com',
password: 'user-password',
tokenUrl: 'https://auth.example.com/oauth/token',
onTokenRefresh: (tokens) => {
// Store tokens for future use
saveTokens(tokens);
}
}
});

OAuth2 with Pre-obtained Token

For tokens obtained via browser-based flows (implicit, authorization code):

// Token obtained from browser OAuth flow
const accessToken = getTokenFromBrowserFlow();

const response = await postPingPostRequest({
payload: message,
baseUrl: 'https://api.example.com',
auth: {
type: 'oauth2',
accessToken: accessToken,
refreshToken: refreshToken, // Optional: for auto-refresh on 401
tokenUrl: 'https://auth.example.com/oauth/token',
clientId: 'your-client-id',
onTokenRefresh: (tokens) => {
// Update stored tokens
updateStoredTokens(tokens);
}
}
});

Retry with Exponential Backoff

Configure automatic retry for failed requests:

const response = await postPingPostRequest({
payload: message,
baseUrl: 'https://api.example.com',
retry: {
maxRetries: 3, // Maximum retry attempts (default: 3)
initialDelayMs: 1000, // Initial delay before first retry (default: 1000)
maxDelayMs: 30000, // Maximum delay between retries (default: 30000)
backoffMultiplier: 2, // Exponential backoff multiplier (default: 2)
retryableStatusCodes: [408, 429, 500, 502, 503, 504], // Status codes to retry
retryOnNetworkError: true, // Retry on network failures
onRetry: (attempt, delay, error) => {
console.log(`Retry attempt ${attempt} after ${delay}ms: ${error.message}`);
}
}
});

Request/Response Hooks

Customize request behavior with hooks:

const response = await postPingPostRequest({
payload: message,
baseUrl: 'https://api.example.com',
hooks: {
// Modify request before sending
beforeRequest: async (params) => {
console.log('Making request to:', params.url);
// Add custom header
return {
...params,
headers: {
...params.headers,
'X-Request-ID': generateRequestId()
}
};
},

// Replace the default fetch implementation
makeRequest: async (params) => {
// Use axios, got, or any HTTP client
const axiosResponse = await axios({
url: params.url,
method: params.method,
headers: params.headers,
data: params.body
});
return {
ok: axiosResponse.status >= 200 && axiosResponse.status < 300,
status: axiosResponse.status,
statusText: axiosResponse.statusText,
headers: axiosResponse.headers,
json: () => axiosResponse.data
};
},

// Process response after receiving
afterResponse: async (response, params) => {
console.log(`Response ${response.status} from ${params.url}`);
return response;
},

// Handle errors
onError: async (error, params) => {
console.error(`Request failed: ${error.message}`);
// Optionally transform the error
return error;
}
}
});

Path Parameters

For operations with path parameters, the generator creates typed parameter classes:

import { UserItemsParameters } from './__gen__/parameters/UserItemsParameters';

// Create parameters with type safety
const params = new UserItemsParameters({
userId: 'user-123',
itemId: 456
});

const response = await getGetUserItem({
baseUrl: 'https://api.example.com',
parameters: params // Replaces {userId} and {itemId} in path
});

Typed Headers

For operations with defined headers, the generator creates typed header classes:

import { ItemRequestHeaders } from './__gen__/headers/ItemRequestHeaders';

const headers = new ItemRequestHeaders({
xCorrelationId: 'corr-123',
xRequestId: 'req-456'
});

const response = await putUpdateUserItem({
baseUrl: 'https://api.example.com',
parameters: params,
payload: itemData,
requestHeaders: headers // Type-safe headers
});

Additional Headers and Query Parameters

Add custom headers or query parameters to any request:

const response = await postPingPostRequest({
payload: message,
baseUrl: 'https://api.example.com',
additionalHeaders: {
'X-Custom-Header': 'value',
'Accept-Language': 'en-US'
},
additionalQueryParams: {
include: 'metadata',
format: 'detailed'
}
});

Multi-Status Responses

For operations that return different payloads based on status code, the generator creates union types:

# AsyncAPI spec with multiple response types
operations:
getItem:
reply:
messages:
- $ref: '#/components/messages/ItemResponse' # 200
- $ref: '#/components/messages/NotFoundError' # 404
const response = await getItemRequest({
baseUrl: 'https://api.example.com',
parameters: params
});

// Response type is union: ItemResponse | NotFoundError
// Use response.status to discriminate
if (response.status === 200) {
console.log('Item:', response.data); // ItemResponse
} else if (response.status === 404) {
console.log('Not found:', response.data); // NotFoundError
}