iToverDose/Software· 19 JUNE 2026 · 12:07

Generate Typed Angular HTTP Clients from OpenAPI in One Command

A new Nx generator eliminates manual HTTP service code in Angular apps by creating tree-shakeable, signal-native API clients directly from OpenAPI specifications. Reduce bundle size and boilerplate without sacrificing type safety.

DEV Community4 min read0 Comments

Angular developers often face a familiar dilemma: You have a perfectly valid OpenAPI specification, but your Angular application still needs HTTP clients to call those endpoints. Common approaches range from manually writing HttpClient services to using bulky code generators that emit thousands of lines of unused code. Neither solution is ideal—one introduces duplication and maintenance overhead, while the other bloats your production bundle.

Enter `@constantant/openapi-resource-gen`, an Nx generator that transforms your OpenAPI 3.x specification into lightweight, tree-shakeable Angular services. Unlike traditional tools, it emits one InjectionToken per endpoint—each in its own file and powered by Angular 22’s native httpResource(). This ensures only the endpoints you actually use are included in your final build.

System Requirements: Angular 22+ and Nx 22+

How One Token Per Endpoint Reduces Bundle Size

The core innovation lies in how bundlers like esbuild operate: they perform tree-shaking at file boundaries. If find-pets-by-status.token.ts is never imported, the entire file—including its type definitions and URL logic—contributes zero bytes to your production bundle. This stands in stark contrast to monolithic service classes that bundle every endpoint, regardless of usage.

Additionally, each generated token functions as a factory that returns an httpResource(). This means your HTTP calls are signal-native from the start, eliminating the need for RxJS, manual subscriptions, or change detection overhead. The result is cleaner code that handles loading states, errors, and automatic re-fetching automatically.

From Manual Services to Generated Signals

Consider the traditional approach most Angular developers follow today:

// ❌ The manual way: a hand-written service
@Injectable({ providedIn: 'root' })
export class PetService {
  private http = inject(HttpClient);
  private base = '

  findByStatus(status: 'available' | 'pending' | 'sold') {
    return this.http.get<Pet[]>(`${this.base}/pet/findByStatus`, {
      params: { status },
    });
  }
}

In the component, this leads to repetitive state management:

@Component({ ... })
export class PetsPageComponent {
  private petService = inject(PetService);
  pets = signal<Pet[]>([]);
  loading = signal(false);
  error = signal<string | null>(null);
  status = signal<'available' | 'pending' | 'sold'>('available');

  constructor() {
    effect(() => {
      this.loading.set(true);
      this.petService.findByStatus(this.status()).subscribe({
        next: (data) => {
          this.pets.set(data);
          this.loading.set(false);
        },
        error: (err) => {
          this.error.set(err.message);
          this.loading.set(false);
        },
      });
    });
  }
}

This pattern introduces several pain points:

  • Type definitions are manually written and prone to drift from the OpenAPI spec.
  • Loading and error states require repetitive boilerplate.
  • The effect + subscribe combination can introduce subtle cancellation issues.
  • Unused endpoints are still bundled, increasing your application’s size.

Now, compare this to the generated alternative:

// ✅ The generated way: inject and call
@Component({ ... })
export class PetsPageComponent {
  private findPetsByStatus = inject(FIND_PETS_BY_STATUS);
  readonly status = signal<'available' | 'pending' | 'sold'>('available');

  // Automatically re-fetches when status() changes
  readonly pets = this.findPetsByStatus(() => ({
    status: this.status()
  }));
}

The generated version provides:

  • Type safety derived directly from the OpenAPI spec.
  • Built-in loading, error, and value signals.
  • Automatic re-fetching when reactive parameters change.
  • Zero boilerplate for state management.

The template reflects this simplicity:

@if (pets.isLoading()) {
  <mat-progress-bar mode="indeterminate" />
}

@for (pet of pets.value() ?? []; track pet.id) {
  <p>{{ pet.name }} — {{ pet.status }}</p>
}

@if (pets.error()) {
  <p class="error">Something went wrong</p>
}

Setting Up the Generator in Your Project

Getting started is straightforward. Follow these steps to integrate the generator into your Angular application:

Step 1: Install the Package

npm install -D @constantant/openapi-resource-gen

Step 2: Generate API Clients

Run the generator and point it to your OpenAPI specification. You can use a local file or a remote HTTPS URL—no intermediate steps required:

npx nx g @constantant/openapi-resource-gen:api-resource \
  --specPath= \
  --outputDir=libs/petstore-data-access/src \
  --baseUrlToken=PETSTORE_BASE_URL \
  --includeMocks \
  --specId=petstore

The generator performs several tasks automatically:

  • Downloads and validates the OpenAPI specification.
  • Uses openapi-typescript to generate a schema.d.ts file.
  • Dereferences all $ref chains with @apidevtools/swagger-parser.
  • Emits one token file per endpoint, organized by OpenAPI tags.

Step 3: Project Structure After Generation

The output directory will resemble:

libs/petstore-data-access/src/
├── schema.d.ts              # TypeScript types from OpenAPI
├── api-base-url.token.ts    # InjectionToken for base URL
├── index.ts                 # Barrel file for re-exports
├── pet/
│   ├── find-pets-by-status.token.ts
│   ├── add-pet.token.ts
│   ├── update-pet.token.ts
│   ├── delete-pet.token.ts
│   └── get-pet-by-id.token.ts
└── user/
    └── ...

Each endpoint gets its own file, grouped by OpenAPI tags. The barrel files ensure clean re-exports.

Step 4: Register Providers

Update your application configuration to register the generated tokens:

import { provideHttpClient } from '@angular/common/http';
import { PETSTORE_BASE_URL, provideFindPetsByStatus, provideGetPetById } from '@myapp/petstore-data-access';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(),
    { provide: PETSTORE_BASE_URL, useValue: ' },
    provideFindPetsByStatus(),
    provideGetPetById(),
    // Only tokens you use are registered—unneeded ones are tree-shaken away
  ],
};

Step 5: Inject and Use

Components can now consume endpoints directly:

@Component({ ... })
export class PetsPageComponent {
  private findPetsByStatus = inject(FIND_PETS_BY_STATUS);
  readonly status = signal<'available' | 'pending' | 'sold'>('available');

  readonly pets = this.findPetsByStatus(() => ({
    status: this.status()
  }));
}

Step 6: Automate Future Updates

Add a generation target to your project.json to simplify re-running the generator when your OpenAPI spec changes:

{
  "targets": {
    "generate": {
      "executor": "@constantant/openapi-resource-gen:generate",
      "options": {
        "specPath": "
        "outputDir": "libs/petstore-data-access/src"
      }
    }
  }
}

Run it with:

npx nx generate

A Smarter Way to Build Angular HTTP Clients

The @constantant/openapi-resource-gen tool offers a compelling alternative to manual service creation or bloated code generators. By leveraging Angular 22’s signal-native httpResource() and Nx’s tree-shaking capabilities, it delivers type-safe, lightweight, and maintainable HTTP clients directly from your OpenAPI specification. As Angular continues to evolve toward a more reactive paradigm, tools like this bridge the gap between specification and implementation, reducing boilerplate while preserving type safety and performance.

AI summary

Stop writing Angular HTTP services by hand. Use @constantant/openapi-resource-gen to create tree-shakeable, signal-native API clients from OpenAPI specs in a single command.

Comments

00
LEAVE A COMMENT
ID #HXI56M

0 / 1200 CHARACTERS

Human check

5 + 4 = ?

Will appear after editor review

Moderation · Spam protection active

No approved comments yet. Be first.