Angular Query

Start by providing an OpenAPI specification and an Orval config file. To use Angular Query, define the client in the Orval config to be angular-query.

Example with Angular Query

import { defineConfig } from 'orval';
export default defineConfig({
petstore: {
output: {
mode: 'tags-split',
target: 'src/petstore.ts',
schemas: 'src/model',
client: 'angular-query',
httpClient: 'angular',
mock: true,
},
input: {
target: './petstore.yaml',
},
},
});

Navigate to the Orval config reference to see all available options.

The Angular Query mode will generate an implementation file with one injectable query function per path in the OpenAPI Specification. By default, Orval uses Angular's native HttpClient via inject(HttpClient) for HTTP requests.

For example, this Swagger specification will generate the following:

// Base operation function
export const showPetById = (
http: HttpClient,
petId: string,
options?: { signal?: AbortSignal | null },
): Promise<Pet> => {
const url = `/pets/${petId}`;
const request$ = http.get<Pet>(url);
if (options?.signal) {
return lastValueFrom(
request$.pipe(takeUntil(fromEvent(options.signal, 'abort'))),
);
}
return lastValueFrom(request$);
};
// Query key factory
export const getShowPetByIdQueryKey = (petId?: string) => {
return [`/pets/${petId}`] as const;
};
// Query options factory
export const getShowPetByIdQueryOptions = <
TData = Awaited<ReturnType<typeof showPetById>>,
TError = unknown,
>(
http: HttpClient,
petId: string,
options?: {
query?: Partial<
CreateQueryOptions<Awaited<ReturnType<typeof showPetById>>, TError, TData>
>;
fetch?: RequestInit;
},
) => {
const { query: queryOptions, fetch: fetchOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getShowPetByIdQueryKey(petId);
const queryFn: QueryFunction<Awaited<ReturnType<typeof showPetById>>> = ({
signal,
}) => showPetById(http, petId, { signal, ...fetchOptions });
return {
queryKey,
queryFn,
enabled: !!petId,
...queryOptions,
} as CreateQueryOptions<
Awaited<ReturnType<typeof showPetById>>,
TError,
TData
>;
};
// Injectable query function
export function injectShowPetById<
TData = Awaited<ReturnType<typeof showPetById>>,
TError = unknown,
>(
petId: string | (() => string),
options?:
| {
query?: Partial<
CreateQueryOptions<
Awaited<ReturnType<typeof showPetById>>,
TError,
TData
>
>;
fetch?: RequestInit;
}
| (() => {
query?: Partial<
CreateQueryOptions<
Awaited<ReturnType<typeof showPetById>>,
TError,
TData
>
>;
fetch?: RequestInit;
}),
): CreateQueryResult<TData, TError> {
const http = inject(HttpClient);
const query = injectQuery(() => {
const _petId = typeof petId === 'function' ? petId() : petId;
const _options = typeof options === 'function' ? options() : options;
return getShowPetByIdQueryOptions(http, _petId, _options);
}) as CreateQueryResult<TData, TError>;
return query;
}

Signal Reactivity

The generated inject* functions support Angular signals out of the box. Parameters can be passed as getter functions, enabling reactive query updates when signals change:

@Component({...})
export class PetDetailComponent {
// Signal-based parameter
petId = signal('1');
// Query automatically re-executes when petId() changes
pet = injectShowPetById(() => this.petId());
// Also works with options for dynamic enabled/disabled
conditionalPet = injectShowPetById(
() => this.petId(),
() => ({
query: { enabled: this.isEnabled() },
}),
);
}

This pattern works for all parameters including query params and options.

Mutations

For POST, PUT, PATCH, and DELETE operations, Orval generates mutation functions:

// Mutation options factory
export const getCreatePetsMutationOptions = <TError = Error, TContext = unknown>(
http: HttpClient,
queryClient: QueryClient,
options?: {
mutation?: CreateMutationOptions<...>;
fetch?: RequestInit;
},
) => { ... };
// Injectable mutation function
export const injectCreatePets = <TError = Error, TContext = unknown>(
options?: {...}
): CreateMutationResult<...> => {
const http = inject(HttpClient);
const queryClient = inject(QueryClient);
// ...
return injectMutation(() => mutationOptions);
};

Usage:

@Component({...})
export class CreatePetComponent {
createPet = injectCreatePets();
onSubmit(pet: CreatePetsBody) {
this.createPet.mutate({ data: pet });
}
}

Query Invalidation

When useInvalidate: true is set, Orval generates helper functions to invalidate queries:

export const invalidateShowPetById = async (
queryClient: QueryClient,
petId: string,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getShowPetByIdQueryKey(petId) },
options,
);
return queryClient;
};

Automatic Mutation Invalidation (Angular Query Only)

The Angular Query client supports declarative, automatic query invalidation when mutations succeed via the mutationInvalidates config:

import { defineConfig } from 'orval';
export default defineConfig({
petstore: {
output: {
client: 'angular-query',
override: {
query: {
useInvalidate: true,
mutationInvalidates: [
{
onMutations: ['createPets'],
invalidates: ['listPets'],
},
{
onMutations: ['deletePet', 'updatePet', 'patchPet'],
invalidates: [
'listPets',
{ query: 'showPetById', params: ['petId'] },
],
},
],
},
},
},
// ...
},
});

This generates an onSuccess handler in the mutation options:

const onSuccess = (data, variables, onMutateResult, context) => {
queryClient.invalidateQueries({ queryKey: getListPetsQueryKey() });
queryClient.invalidateQueries({
queryKey: getShowPetByIdQueryKey(variables.petId),
});
mutationOptions?.onSuccess?.(data, variables, onMutateResult, context);
};

Param-based invalidation: With { query: 'showPetById', params: ['petId'] }, when deletePet({ petId: '123' }) succeeds, only the query for pet 123 is invalidated—not all showPetById queries.

Usage: To get automatic invalidation, use the generated inject* mutation functions:

@Component({
template: `
<ul>
@for (pet of pets.data(); track pet.id) {
<li>
{{ pet.name }}
<button (click)="onDelete(pet.id)">Delete</button>
</li>
}
</ul>
`,
})
export class PetListComponent {
// Query - will be automatically invalidated after mutations
pets = injectListPets();
// Mutation - automatic invalidation is built into the generated options
deletePet = injectDeletePet();
onDelete(petId: string) {
// After success, listPets and showPetById(petId) are automatically invalidated
this.deletePet.mutate({ petId });
}
}

How to Use Other Queries

Given the following configuration, Orval will generate query and infinite query functions with a nextId query parameter. It is also possible to override the config for every query with the options field.

import { defineConfig } from 'orval';
export default defineConfig({
petstore: {
output: {
...
override: {
query: {
useQuery: true,
useInfinite: true,
useInfiniteQueryParam: 'nextId',
options: {
staleTime: 10000,
},
},
},
},
...
},
});

If needed, it is also possible to override the query options for a single operation or tag:

import { defineConfig } from 'orval';
export default defineConfig({
petstore: {
output: {
...
override: {
operations: {
listPets: {
query: {
...
},
}
},
},
}
...
},
});

Go here for a full example

Was this page helpful?