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
29 changes: 29 additions & 0 deletions docs/generators/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,35 @@ This is supported through the following inputs: [`asyncapi`](#inputs), [`openapi

It supports the following languages; `typescript`

## Companion Interface

Every generated parameter model file exports **two** symbols: the parameter
class (`<Name>Parameters`) and a plain-data companion interface
(`<Name>ParametersInterface`) declared above it. The class constructor takes the
interface (`constructor(input: <Name>ParametersInterface)`), so the two always
stay in sync.

```typescript
export { FindPetsByStatusParameters, FindPetsByStatusParametersInterface };
```

This lets you pass a **plain object** wherever a channel expects parameters —
you do not have to construct the class yourself:

```typescript
// Both of these are accepted by every generated channel helper:
await publishToUserSignedup({ message, parameters: { myParameter: 'test', enumParameter: 'openapi' }, nc });
await publishToUserSignedup({ message, parameters: new UserSignedupParameters({ myParameter: 'test', enumParameter: 'openapi' }), nc });
```

Channel consumers type their parameter argument as the union
`<Name>ParametersInterface | <Name>Parameters` and normalize it to a class
instance internally (via an `instanceof` guard) before using the rich class
behavior (`getChannelWithParameters`, serialization, etc.). The plain-object
form is purely an ergonomic convenience; the generated code always operates on a
class instance. See the [protocols documentation](../protocols) for how each
channel accepts parameters.

## Inputs

### `asyncapi`
Expand Down
5 changes: 5 additions & 0 deletions examples/openapi-http-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ created.data.connectUrl; // typed
const params = new GetV2ConnectReferenceIdParameters({referenceId: 'ref_123'});
const connect = await http_client.getV2ConnectReferenceId({server, parameters: params});
connect.data.safepayAccountId; // typed

// ...or, more ergonomically, pass a plain object — every parameter model also
// exports a companion interface, and channels accept `Interface | Class` and
// normalize internally. No need to construct the model yourself:
await http_client.getV2ConnectReferenceId({server, parameters: {referenceId: 'ref_123'}});
```

Every function returns `HttpClientResponse<T>` where `data` is the unmarshalled, typed response model, alongside `status`, `headers`, and pagination helpers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export {InitializeRequest};
export {InitializeModel};
export {GetConnectModel};
export {BankAccount};
import {GetV2ConnectReferenceIdParameters} from './../parameter/GetV2ConnectReferenceIdParameters';
import {GetV2UsersSafepayAccountIdBankAccountsParameters} from './../parameter/GetV2UsersSafepayAccountIdBankAccountsParameters';
import {GetV2ConnectReferenceIdParameters, GetV2ConnectReferenceIdParametersInterface} from './../parameter/GetV2ConnectReferenceIdParameters';
import {GetV2UsersSafepayAccountIdBankAccountsParameters, GetV2UsersSafepayAccountIdBankAccountsParametersInterface} from './../parameter/GetV2UsersSafepayAccountIdBankAccountsParameters';
export {GetV2ConnectReferenceIdParameters};
export {GetV2UsersSafepayAccountIdBankAccountsParameters};

Expand Down
22 changes: 13 additions & 9 deletions examples/openapi-http-client/src/generated/http_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {InitializeRequest} from './payload/InitializeRequest';
import {InitializeModel} from './payload/InitializeModel';
import {GetConnectModel} from './payload/GetConnectModel';
import {BankAccount} from './payload/BankAccount';
import {GetV2ConnectReferenceIdParameters} from './parameter/GetV2ConnectReferenceIdParameters';
import {GetV2UsersSafepayAccountIdBankAccountsParameters} from './parameter/GetV2UsersSafepayAccountIdBankAccountsParameters';
import {GetV2ConnectReferenceIdParameters, GetV2ConnectReferenceIdParametersInterface} from './parameter/GetV2ConnectReferenceIdParameters';
import {GetV2UsersSafepayAccountIdBankAccountsParameters, GetV2UsersSafepayAccountIdBankAccountsParametersInterface} from './parameter/GetV2UsersSafepayAccountIdBankAccountsParameters';
import {PostV2ConnectHeaders} from './headers/PostV2ConnectHeaders';

// ============================================================================
Expand Down Expand Up @@ -1119,7 +1119,7 @@ async function postV2Connect(context: PostV2ConnectContext): Promise<HttpClientR

// Parse response
const rawData = await response.json();
const responseData = PostV2ConnectResponse_200.unmarshal(rawData);
const responseData = PostV2ConnectResponse_200.unmarshal(JSON.stringify(rawData));

// Extract response metadata
const responseHeaders = extractHeaders(response);
Expand Down Expand Up @@ -1148,7 +1148,7 @@ async function postV2Connect(context: PostV2ConnectContext): Promise<HttpClientR
}

export interface GetV2ConnectReferenceIdContext extends HttpClientContext {
parameters: { getChannelWithParameters: (path: string) => string };
parameters: GetV2ConnectReferenceIdParametersInterface | GetV2ConnectReferenceIdParameters;
requestHeaders?: { marshal: () => string };
}

Expand All @@ -1163,6 +1163,8 @@ async function getV2ConnectReferenceId(context: GetV2ConnectReferenceIdContext):
...context,
};

const parameters = context.parameters instanceof GetV2ConnectReferenceIdParameters ? context.parameters : new GetV2ConnectReferenceIdParameters(context.parameters);

// Validate OAuth2 config if present
if (config.auth?.type === 'oauth2' && AUTH_FEATURES.oauth2) {
validateOAuth2Config(config.auth);
Expand All @@ -1174,7 +1176,7 @@ async function getV2ConnectReferenceId(context: GetV2ConnectReferenceIdContext):
: { 'Content-Type': 'application/json', ...config.additionalHeaders } as Record<string, string | string[]>;

// Build URL
let url = buildUrlWithParameters(config.server, '/v2/connect/{referenceId}', context.parameters);
let url = buildUrlWithParameters(config.server, '/v2/connect/{referenceId}', parameters);
url = applyQueryParams(config.queryParams, url);

// Apply pagination (can affect URL and/or headers)
Expand Down Expand Up @@ -1242,7 +1244,7 @@ async function getV2ConnectReferenceId(context: GetV2ConnectReferenceIdContext):

// Parse response
const rawData = await response.json();
const responseData = GetV2ConnectReferenceIdResponse_200.unmarshal(rawData);
const responseData = GetV2ConnectReferenceIdResponse_200.unmarshal(JSON.stringify(rawData));

// Extract response metadata
const responseHeaders = extractHeaders(response);
Expand Down Expand Up @@ -1271,7 +1273,7 @@ async function getV2ConnectReferenceId(context: GetV2ConnectReferenceIdContext):
}

export interface GetV2UsersSafepayAccountIdBankAccountsContext extends HttpClientContext {
parameters: { getChannelWithParameters: (path: string) => string };
parameters: GetV2UsersSafepayAccountIdBankAccountsParametersInterface | GetV2UsersSafepayAccountIdBankAccountsParameters;
requestHeaders?: { marshal: () => string };
}

Expand All @@ -1286,6 +1288,8 @@ async function getV2UsersSafepayAccountIdBankAccounts(context: GetV2UsersSafepay
...context,
};

const parameters = context.parameters instanceof GetV2UsersSafepayAccountIdBankAccountsParameters ? context.parameters : new GetV2UsersSafepayAccountIdBankAccountsParameters(context.parameters);

// Validate OAuth2 config if present
if (config.auth?.type === 'oauth2' && AUTH_FEATURES.oauth2) {
validateOAuth2Config(config.auth);
Expand All @@ -1297,7 +1301,7 @@ async function getV2UsersSafepayAccountIdBankAccounts(context: GetV2UsersSafepay
: { 'Content-Type': 'application/json', ...config.additionalHeaders } as Record<string, string | string[]>;

// Build URL
let url = buildUrlWithParameters(config.server, '/v2/users/{safepayAccountId}/bank-accounts', context.parameters);
let url = buildUrlWithParameters(config.server, '/v2/users/{safepayAccountId}/bank-accounts', parameters);
url = applyQueryParams(config.queryParams, url);

// Apply pagination (can affect URL and/or headers)
Expand Down Expand Up @@ -1365,7 +1369,7 @@ async function getV2UsersSafepayAccountIdBankAccounts(context: GetV2UsersSafepay

// Parse response
const rawData = await response.json();
const responseData = GetV2UsersSafepayAccountIdBankAccountsResponse_200.unmarshal(rawData);
const responseData = GetV2UsersSafepayAccountIdBankAccountsResponse_200.unmarshal(JSON.stringify(rawData));

// Extract response metadata
const responseHeaders = extractHeaders(response);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@

interface GetV2ConnectReferenceIdParametersInterface {
referenceId: string
}
class GetV2ConnectReferenceIdParameters {
private _referenceId: string;

constructor(input: {
referenceId: string,
}) {
constructor(input: GetV2ConnectReferenceIdParametersInterface) {
this._referenceId = input.referenceId;
}

Expand Down Expand Up @@ -117,4 +118,4 @@ class GetV2ConnectReferenceIdParameters {
return result;
}
}
export { GetV2ConnectReferenceIdParameters };
export { GetV2ConnectReferenceIdParameters, GetV2ConnectReferenceIdParametersInterface };
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@

interface GetV2UsersSafepayAccountIdBankAccountsParametersInterface {
safepayAccountId: string
}
class GetV2UsersSafepayAccountIdBankAccountsParameters {
private _safepayAccountId: string;

constructor(input: {
safepayAccountId: string,
}) {
constructor(input: GetV2UsersSafepayAccountIdBankAccountsParametersInterface) {
this._safepayAccountId = input.safepayAccountId;
}

Expand Down Expand Up @@ -117,4 +118,4 @@ class GetV2UsersSafepayAccountIdBankAccountsParameters {
return result;
}
}
export { GetV2UsersSafepayAccountIdBankAccountsParameters };
export { GetV2UsersSafepayAccountIdBankAccountsParameters, GetV2UsersSafepayAccountIdBankAccountsParametersInterface };
8 changes: 8 additions & 0 deletions examples/openapi-http-client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ async function main() {
connect.data.status
);

// Ergonomic alternative: pass a plain object satisfying the parameter
// interface. The channel normalizes it to a class instance internally, so
// you get identical behavior without constructing the model yourself.
const connectPlain = await safepay.getV2ConnectReferenceId({
parameters: {referenceId: 'ref_123'}
});
console.log('safepayAccountId (plain object):', connectPlain.data.safepayAccountId);

// The standalone channel functions remain available for one-off calls where
// constructing a client is unnecessary.
await http_client.postV2Connect({server, payload: connectBody});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import {ChannelFunctionTypes} from '../..';
import {SingleFunctionRenderType} from '../../../../../types';
import {pascalCase} from '../../../utils';
import {RenderRegularParameters} from '../../types';
import {renderChannelJSDoc} from '../../utils';
import {
parameterInstanceExpression,
parameterUnionType,
renderChannelJSDoc
} from '../../utils';

export function renderPublishExchange({
topic,
Expand All @@ -20,7 +24,7 @@ export function renderPublishExchange({
exchange: string | undefined;
}>): SingleFunctionRenderType {
const addressToUse = channelParameters
? `parameters.getChannelWithParameters('${topic}')`
? `${parameterInstanceExpression({modelName: channelParameters.type, source: 'parameters'})}.getChannelWithParameters('${topic}')`
: `'${topic}'`;
let messageMarshalling = 'message.marshal()';
if (messageModule) {
Expand Down Expand Up @@ -59,7 +63,7 @@ channel.publish(exchange, routingKey, Buffer.from(dataToSend), publishOptions);`
? [
{
parameter: `parameters`,
parameterType: `parameters: ${channelParameters.type}`,
parameterType: `parameters: ${parameterUnionType(channelParameters.type)}`,
jsDoc: ' * @param parameters for topic substitution'
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import {ChannelFunctionTypes} from '../..';
import {SingleFunctionRenderType} from '../../../../../types';
import {pascalCase} from '../../../utils';
import {RenderRegularParameters} from '../../types';
import {renderChannelJSDoc} from '../../utils';
import {
parameterInstanceExpression,
parameterUnionType,
renderChannelJSDoc
} from '../../utils';

export function renderPublishQueue({
topic,
Expand All @@ -17,7 +21,7 @@ export function renderPublishQueue({
deprecated
}: RenderRegularParameters): SingleFunctionRenderType {
const addressToUse = channelParameters
? `parameters.getChannelWithParameters('${topic}')`
? `${parameterInstanceExpression({modelName: channelParameters.type, source: 'parameters'})}.getChannelWithParameters('${topic}')`
: `'${topic}'`;
let messageMarshalling = 'message.marshal()';
if (messageModule) {
Expand Down Expand Up @@ -56,7 +60,7 @@ channel.sendToQueue(queue, Buffer.from(dataToSend), publishOptions);`;
? [
{
parameter: `parameters`,
parameterType: `parameters: ${channelParameters.type}`,
parameterType: `parameters: ${parameterUnionType(channelParameters.type)}`,
jsDoc: ' * @param parameters for topic substitution'
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import {ChannelFunctionTypes} from '../..';
import {SingleFunctionRenderType} from '../../../../../types';
import {pascalCase} from '../../../utils';
import {RenderRegularParameters} from '../../types';
import {getValidationFunctions, renderChannelJSDoc} from '../../utils';
import {
getValidationFunctions,
parameterInstanceExpression,
parameterUnionType,
renderChannelJSDoc
} from '../../utils';

export function renderSubscribeQueue({
topic,
Expand All @@ -18,7 +23,7 @@ export function renderSubscribeQueue({
}: RenderRegularParameters): SingleFunctionRenderType {
const includeValidation = payloadGenerator.generator.includeValidation;
const addressToUse = channelParameters
? `parameters.getChannelWithParameters('${topic}')`
? `${parameterInstanceExpression({modelName: channelParameters.type, source: 'parameters'})}.getChannelWithParameters('${topic}')`
: `'${topic}'`;
const messageUnmarshalling = `${messageModule ?? messageType}.unmarshal(receivedData)`;
messageType = messageModule ? `${messageModule}.${messageType}` : messageType;
Expand Down Expand Up @@ -95,7 +100,7 @@ channel.consume(queue, (msg) => {
? [
{
parameter: `parameters`,
parameterType: `parameters: ${channelParameters.type}`,
parameterType: `parameters: ${parameterUnionType(channelParameters.type)}`,
jsDoc: ' * @param parameters for topic substitution'
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import {
defaultTypeScriptChannelsGenerator,
RenderRegularParameters
} from '../../types';
import {getValidationFunctions, renderChannelJSDoc} from '../../utils';
import {
getValidationFunctions,
parameterInstanceExpression,
parameterUnionType,
renderChannelJSDoc
} from '../../utils';

export function renderFetch({
topic,
Expand All @@ -27,7 +32,7 @@ export function renderFetch({
}>): SingleFunctionRenderType {
const includeValidation = payloadGenerator.generator.includeValidation;
const addressToUse = channelParameters
? `parameters.getChannelWithParameters('${topic}')`
? `${parameterInstanceExpression({modelName: channelParameters.type, source: 'parameters'})}.getChannelWithParameters('${topic}')`
: `'${topic}'`;
const messageUnmarshalling = `${messageModule ?? messageType}.unmarshal(receivedData)`;
messageType = messageModule ? `${messageModule}.${messageType}` : messageType;
Expand All @@ -49,7 +54,7 @@ export function renderFetch({
? [
{
parameter: `parameters`,
parameterType: `parameters: ${channelParameters.type}`,
parameterType: `parameters: ${parameterUnionType(channelParameters.type)}`,
jsDoc: ' * @param parameters for listening'
}
]
Expand Down
Loading
Loading