Skip to content

Angular client places accept before request body in multi-content response overloads #3349

Description

@montella1507

Description

Thanks for fixing the Angular HttpClient call body placement. I tested this with orval@8.10.0 against our generated Angular client and it does fix the main runtime issue: this.http.post/put/patch(...) now receives the request body as the positional body argument before the options object.

There still seems to be a related signature/order issue for operations with:

  • a request body,
  • route/path parameters,
  • multiple response content types / accept overloads.

Example generated output:

postApiV1ReservationConfirmationsByTokenConfirmationToken(
  confirmationToken: string,
  accept: 'application/json',
  nullConfirmReservationResourceRequest?: null | ConfirmReservationResourceRequest,
  options?: HttpClientOptions
): Observable<ReservationConfirmationResultResponse>;

The actual HttpClient call is now correct:

return this.http.post<ReservationConfirmationResultResponse>(
  `/api/v1/reservation-confirmations/by-token/${confirmationToken}`,
  nullConfirmReservationResourceRequest,
  {
    ...options,
    responseType: 'json',
    headers,
  },
);

But the generated public method signature still places accept before the request body. This is inconsistent with the rest of the generated body-verb methods and with the expected call shape where the request body remains the second user-facing argument after path params

postApiV1ReservationConfirmationsByTokenConfirmationToken(
  confirmationToken: string,
  nullConfirmReservationResourceRequest: null | ConfirmReservationResourceRequest | undefined,
  accept: 'application/json',
  options?: HttpClientOptions
): Observable<ReservationConfirmationResultResponse>;

This matters because existing callers naturally pass the body as the second argument. With the current generated overload order, TypeScript callers get an API break, and JS/any callers can accidentally pass a body object into accept, which then reaches accept.includes(...) and can throw at runtime.

So #3335 appears to fix the HttpClient call expression, but not the overload/implementation parameter order for this multi-content Angular case.

Output client

angular

Configuration (orval.config)

import { defineConfig } from 'orval';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const configDirectory = dirname(fileURLToPath(import.meta.url));
const workspaceRoot = resolve(configDirectory, '../../..');
const openApiDocumentPath = resolve(workspaceRoot, 'dist/apps/api/openapi/api.json');
const generatedRoot = resolve(configDirectory, 'src/generated');

export default defineConfig({
leveraApi: {
input: {
target: openApiDocumentPath,
},
output: {
mode: 'tags-split',
target: resolve(generatedRoot, 'http-client/index.ts'),
schemas: resolve(generatedRoot, 'models'),
client: 'angular',
override: {
angular: {
retrievalClient: 'both',
provideIn: 'root',
},
zod: {
generate: {
body: true,
response: true,
query: true,
param: true,
header: true,
},
},
},
clean: true,
},
},
leveraApiZod: {
input: {
target: openApiDocumentPath,
},
output: {
mode: 'single',
target: resolve(generatedRoot, 'schemas/index.ts'),
client: 'zod',
clean: false,
},
},
});

Environment

Run the command above and paste the output here.
System:
OS: macOS 26.3.1
CPU: (14) arm64 Apple M4 Pro
Memory: 967.80 MB / 48.00 GB
Shell: 5.9 - /bin/zsh
npmPackages:
@angular/common: ~21.2.9 => 21.2.9
@angular/core: ~21.2.9 => 21.2.9
orval: 8.10.0
zod: ^4.1.11 => 4.3.6

Expected behavior

No response

Actual behavior

No response

OpenAPI document (minimal, if applicable)

openapi: 3.0.3
info:
  title: Demo
  version: 0.0.0
paths: {}

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    angularRelated to Angular generation issues

    Type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions