@metaengine/openapi-angular
v0.9.9
Published
Generate TypeScript/Angular services and models from OpenAPI specifications with httpResource (Angular 19.2+) and Signal-based data fetching support
Maintainers
Readme
@metaengine/openapi-angular
Generate TypeScript/Angular services and models from OpenAPI specifications.
Features
- ✅ Angular 14+ - Modern Angular with RxJS observables
- ✅ httpResource (Angular 19.2+) - Signal-based data fetching with automatic request management
- ✅ TypeScript - Fully typed API clients and models
- ✅ Dependency Injection - Injectable services with configurable scope
- ✅ HttpClient Integration - Native Angular HTTP client
- ✅ Error Handling - Smart error handling with interceptors
- ✅ Modern inject() - Support for functional injection
- ✅ Tree-shakeable - Optimized bundle size with separate files
Installation
npm install --save-dev @metaengine/openapi-angularOr use directly with npx:
npx @metaengine/openapi-angular <input> <output>Requirements
- Node.js 14.0 or later
- .NET 8.0 or later runtime (Download)
- Angular 14.0 or later (for generated code)
Usage
With npm scripts (Recommended when installed locally)
If you installed the package with npm install, add a script to your package.json:
{
"scripts": {
"generate:api": "metaengine-openapi-angular api.yaml ./src/app/api --inject-function --error-handling --documentation"
}
}Then run:
npm run generate:apiWith npx (One-off usage or without installation)
Use npx for trying out the tool or in CI/CD pipelines:
npx @metaengine/openapi-angular <input> <output> [options]Quick Examples
# Recommended (follows Angular style guide)
npx @metaengine/openapi-angular api.yaml ./src/app/api \
--inject-function \
--error-handling \
--documentation
# Basic (minimal setup)
npx @metaengine/openapi-angular api.yaml ./src/app/api
# From URL
npx @metaengine/openapi-angular https://api.example.com/openapi.json ./src/app/api \
--inject-function \
--documentation
# Filter by tags (only specific endpoints)
npx @metaengine/openapi-angular api.yaml ./src/app/api \
--include-tags users,auth \
--inject-function
# Advanced (custom DI scope with strict validation)
npx @metaengine/openapi-angular api.yaml ./src/app/api \
--inject-function \
--provided-in any \
--strict-validation \
--documentationNote: When the package is installed locally, npx will use that version instead of downloading a new one.
CLI Options
| Option | Description | Default |
|--------|-------------|---------|
| --include-tags <tags> | Filter by OpenAPI tags (comma-separated, case-insensitive) | - |
| --provided-in <value> | Angular injection scope (root, any, platform) | - |
| --base-url-token <name> | Injection token name for base URL | BASE_URL |
| --options-threshold <n> | Parameter count for options object | 4 |
| --documentation | Generate JSDoc comments | false |
| --inject-function | Use inject() instead of constructor injection | false |
| --http-resource | Use httpResource with Signals for HTTP calls | false |
| --error-handling | Enable smart error handling | false |
| --strict-validation | Enable strict OpenAPI validation | false |
| --verbose | Enable verbose logging | false |
| --help, -h | Show help message | - |
Generated Code Structure
The generator creates a clean, modular structure with separate files for each model and service, optimized for tree-shaking:
output/
├── models/ # One file per model
│ ├── user.ts # export interface User { ... }
│ ├── product.ts # export interface Product { ... }
│ ├── order.ts # export interface Order { ... }
│ └── ...
├── services/ # One file per service/tag
│ ├── users.service.ts # UsersService with all user operations
│ ├── products.service.ts # ProductsService with all product operations
│ ├── orders.service.ts # OrdersService with all order operations
│ ├── base-api.service.ts # Base service with common functionality
│ └── ...
├── alias-types.ts # Type aliases from OpenAPI spec
├── dictionary-types.ts # Dictionary/map types
└── union-types.ts # Union types for complex schemasExample Generated Code
Model (models/user.ts)
export interface User {
id: string;
email: string;
name: string;
created_at: string;
roles?: string[];
}Service (services/users.service.ts)
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { BaseApiService } from './base-api.service';
import { User } from '../models/user';
import { CreateUserRequest } from '../models/create-user-request';
import { UsersListResponse } from '../models/users-list-response';
@Injectable({ providedIn: 'root' })
export class UsersService extends BaseApiService {
/**
* Get list of users
* @param {number} limit Maximum number of users to return
* @param {number} offset Offset for pagination
* @returns {Observable<UsersListResponse>} Observable containing the users list
*/
listUsers(limit?: number, offset?: number): Observable<UsersListResponse> {
const params: Record<string, any> = {};
if (limit !== undefined) params['limit'] = limit;
if (offset !== undefined) params['offset'] = offset;
return this.createRequest(() => this.http.get<UsersListResponse>(
this.buildUrl('/users'),
{ params: this.createParams(params) }
), 'listUsers');
}
/**
* Get a user by ID
* @param {string} userId User ID
* @returns {Observable<User>} Observable containing the user
*/
getUser(userId: string): Observable<User> {
return this.createRequest(() => this.http.get<User>(
this.buildUrl(`/users/${userId}`)
), 'getUser');
}
/**
* Create a new user
* @param {CreateUserRequest} request User creation request
* @returns {Observable<User>} Observable containing the created user
*/
createUser(request: CreateUserRequest): Observable<User> {
return this.createRequest(() => this.http.post<User>(
this.buildUrl('/users'),
request
), 'createUser');
}
}httpResource Support (Angular 19.2+)
When using --http-resource, the generator creates Signal-based resource methods alongside traditional Observable methods for GET operations:
import { Injectable, Signal } from '@angular/core';
import { Observable } from 'rxjs';
import { httpResource, HttpResourceRef } from '@angular/common/http';
import { BaseApiService } from './base-api.service';
import { User } from '../models/user';
@Injectable({ providedIn: 'root' })
export class UsersService extends BaseApiService {
// Traditional Observable method (always available)
getUser(userId: string): Observable<User> {
return this.createRequest(() => this.http.get<User>(
this.buildUrl(`/users/${userId}`)
), 'getUser');
}
// Signal-based httpResource method (with --http-resource flag)
getUserResource(userId: Signal<string | undefined>): HttpResourceRef<User | undefined> {
return httpResource<User>(
() => {
const userIdValue = userId();
if (typeof userIdValue === 'undefined') {
return undefined;
}
return {
url: this.buildUrl(`/users/${userIdValue}`)
};
});
}
}Benefits of httpResource:
- Automatic request lifecycle management
- Reactive updates when Signal inputs change
- Prevents requests when required parameters are undefined
- Perfect for create/edit forms with initially undefined inputs
- Smaller bundle size compared to RxJS for simple GET requests
Usage in components:
export class UserDetailsComponent {
private userIdSignal = signal<string | undefined>(undefined);
// Automatically refetches when userIdSignal changes
userResource = inject(UsersService).getUserResource(this.userIdSignal);
loadUser(id: string) {
this.userIdSignal.set(id); // Triggers automatic refetch
}
}License
MIT
Support
For issues and feature requests, please visit: https://github.com/meta-engine/openapi-angular/issues
