ng-openapi-gen

repository·master·Indexed 19 days ago

https://github.com/cyclosproject/ng-openapi-gen

An OpenAPI 3.0 and 3.1 code generator for Angular 16+ that generates TypeScript model interfaces and web service clients. It supports CLI usage, Node.js script integration, and custom Handlebars templates for code generation. Features include support for functional API calls for better tree-shaking, tag-based services, and vendor extensions like x-operation-name and x-enumNames.

Tokens
6.5K
Snippets
18
Records
27
Agent score
61%

What's inside ng-openapi-gen

  1. How functional API calls work with the Api service

    master

    By default (since version 1.0), ng-openapi-gen generates individual functions for each API operation and provides a single @Injectable service (named Api by default, configurable via apiService) to invoke them. This approach is more tree-shakeable for large APIs because only the specific functions you import and use will be bundled.

    To use this pattern, inject the Api service and use its .invoke() method, passing the generated operation function as the first argument.

    import { Component, inject, OnInit, signal } from '@angular/core';
    import { Api } from './api/api';
    import { getResults } from './api/fn/operations/get-results';
    import { Result } from './api/models';
    
    @Component({
      selector: 'app-root',
      imports: [RouterOutlet],
      templateUrl: './app.html',
      styleUrl: './app.css',
    })
    export class App implements OnInit {
      protected readonly results = signal<Result[] | null>(null);
    
      private api = inject(Api);
    
      async ngOnInit() {
        this.results.set(await this.api.invoke(getResults, { limit: 5 }));
      }
    }
  2. How tag-based services work

    master

    You can configure the generator to create an @Injectable service for each API tag by setting "services": true. This provides a cleaner, more object-oriented API (e.g., resultsService.getResults(...)) but may increase bundle size because injecting a service will bundle all operations associated with that tag, even if only one is used.

    import { Component, inject, OnInit, signal } from '@angular/core';
    import { Result } from './api/models';
    import { ResultsService } from './api/services';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.html',
      styleUrl: './app.css',
    })
    export class App implements OnInit {
      protected readonly results = signal<Result[] | null>(null);
    
      private resultsService = inject(ResultsService);
    
      async ngOnInit() {
        this.results.set(await this.resultsService.getResults({ limit: 5 }));
      }
    }
  3. Automate API code generation with NPM scripts

    master

    It is recommended to avoid committing generated code to version control (e.g., Git) if your API definition changes frequently. Instead, automate the generation process using NPM scripts to ensure your local code stays in sync with your OpenAPI specification.

    Single Configuration

    Add a generate:api script to your package.json and chain it to your start and build commands.

    Multiple Configuration Files

    If you have multiple OpenAPI specs, you can chain multiple ng-openapi-gen calls using the -c flag to specify different configuration files.

    {
      "scripts": {
        "generate:api": "npm run generate:api:a && npm run generate:api:b",
        "generate.api:a": "ng-openapi-gen -c api-a.json",
        "generate.api:b": "ng-openapi-gen -c api-b.json",
        "start": "npm run generate:api && npm run ng -- serve",
        "build": "npm run generate:api && npm run ng -- build -prod"
      }
    }
  4. Install and run ng-openapi-gen via CLI

    master

    You can install ng-openapi-gen globally or locally in your project. To use the CLI, provide an --input (the OpenAPI specification file) and an --output (the directory where generated code should be placed).

    Example of a global installation and execution:

    $ npm install -g ng-openapi-gen
    $ ng-openapi-gen --input my-api.yaml --output my-app/src/app/api
  5. Specify the root URL for web service endpoints

    master

    To override the default server URL from the OpenAPI spec, you can configure the ApiConfiguration class. There are two recommended ways to do this in an Angular application:

    Add the provider to your ApplicationConfig in your bootstrap file.

    2. Injecting ApiConfiguration directly

    Inject the ApiConfiguration instance into a component (e.g., your bootstrap component) and set the rootUrl property during initialization.

    // Method 1: Using provideApiConfiguration
    import { ApplicationConfig } from '@angular/core';
    import { provideApiConfiguration } from './api/api-configuration';
    
    export const appConfig: ApplicationConfig = {
      providers: [
        provideApiConfiguration('http://localhost:3000/api')
      ]
    };
    
    // Method 2: Injecting and setting directly
    import { Component, inject, OnInit } from '@angular/core';
    import { ApiConfiguration } from './api/api-configuration';
    
    @Component({
      selector: 'app-root',
      template: '...'
    })
    export class App implements OnInit {
      private apiConfiguration = inject(ApiConfiguration);
    
      async ngOnInit() {
        this.apiConfiguration.rootUrl = 'http://localhost:3000/api';
      }
    }
  6. Customize code generation with Handlebars templates

    master

    You can override the default code generation logic by providing your own Handlebars templates.

    1. Copy the required .handlebars files from the project's templates folder into a directory in your project (e.g., src/templates).
    2. Modify the files to suit your needs.
    3. In your ng-openapi-gen.json configuration file, set the templates key to point to your directory.

    Custom Handlebars Helpers

    You can also add custom logic to your templates by providing a handlebars.js file in the same directory as your templates. This file must export a function that receives the Handlebars instance.

    // ng-openapi-gen.json
    {
      "templates": "src/templates"
    }
    
    // src/templates/handlebars.js
    module.exports = function(handlebars) {
      handlebars.registerHelper('loud', function (aString) {
        return aString.toUpperCase();
      });
    };
    
    // src/templates/object.handlebars
    import { MyBaseModel } from 'src/app/my-base-model';
    export interface {{typeName}} extends MyBaseModel {
    {{#properties}}
    {{{tsComments}}}{{{identifier}}}{{^required}}?{{/required}}: {{{type}}};
    {{/properties}}
    }
  7. Pass request headers and customize requests using Angular Interceptors

    master

    To handle authentication (e.g., Bearer tokens), API keys, or centralized error handling for the generated API, use a standard Angular HttpInterceptorFn. Since the generated code uses Angular's HttpClient, interceptors will automatically apply to all generated service calls.

    1. Create a functional interceptor.
    2. Register it in your app.config.ts using provideHttpClient(withInterceptors([...])).
    import { HttpInterceptorFn } from '@angular/common/http';
    
    // 1. Define the interceptor
    export const API_INTERCEPTOR: HttpInterceptorFn = (req, next) => {
      const authReq = req.clone({ 
        setHeaders: { Authorization: `Bearer YOUR_TOKEN` } 
      });
      return next(authReq);
    };
    
    // 2. Register it in app.config.ts
    import { ApplicationConfig } from '@angular/core';
    import { provideHttpClient, withInterceptors } from '@angular/common/http';
    import { API_INTERCEPTOR } from './api-interceptor';
    
    export const appConfig: ApplicationConfig = {
      providers: [
        provideHttpClient(withInterceptors([API_INTERCEPTOR])),
      ],
    };
  8. Develop and test ng-openapi-gen locally

    master

    If you are contributing to ng-openapi-gen, follow these steps to link your local build to other Node projects for testing:

    1. Build the project to generate the dist folder.
    2. Navigate to the dist folder.
    3. Run npm link to make the local build globally available.

    Note: The project uses vitest for testing, which runs directly against the TypeScript source.

    npm run build
    cd dist
    npm link
  9. Configure ng-openapi-gen via JSON file

    master

    If a ng-openapi-gen.json file exists in your current directory, the CLI will use it automatically. You can also specify a custom config file using the --config or -c flag.

    Common configuration options include:

    • input: Path to the OpenAPI specification (required).
    • output: Path to the output directory (defaults to src/app/api).
    • ignoreUnusedModels: Boolean to skip unused models.

    Note: CLI arguments can be passed in camel case (e.g., --includeTags) or kebab case (e.g., --exclude-tags).

    {
      "$schema": "node_modules/ng-openapi-gen/ng-openapi-gen-schema.json",
      "input": "my-file.json",
      "output": "my-app/src/app/api",
      "ignoreUnusedModels": false
    }
  10. Use CLI arguments to override configuration settings

    master

    The ng-openapi-gen CLI allows you to override any setting defined in your configuration file by passing the corresponding argument via the command line.

    Arguments can be provided using their original camelCase name or their kebab-case equivalent. For example, if you want to change the serviceSuffix defined in your JSON config, you can use either --serviceSuffix or --service-suffix.

    Key behaviors:

    • Configuration File: By default, the generator looks for ng-openapi-gen.json in the current directory. You can specify a custom file using -c or --config.
    • Input Requirement: An OpenAPI specification input is required. If you do not provide an --input argument, you must provide a valid configuration file that contains an input property.
    • Mnemonic Shortcuts: Certain arguments have short flags, such as -i for --input and -o for --output (though these are mapped via internal mnemonics).
    # Example: Overriding serviceSuffix via CLI
    ng-openapi-gen --serviceSuffix MyCustomSuffix
    
    # Example: Using a custom configuration file
    ng-openapi-gen --config ./custom-config.json
    
    # Example: Providing input directly without a config file
    ng-openapi-gen --input ./path/to/openapi.yaml
    
    # Example: Using kebab-case for arguments
    ng-openapi-gen --service-suffix MyCustomSuffix
  11. Run ng-openapi-gen from a Node.js script

    master

    For more control, you can integrate the generator directly into your build scripts using the NgOpenApiGen class. It is recommended to use json-schema-ref-parser to bundle and dereference your OpenAPI specification before passing it to the generator.

    import $RefParser from 'json-schema-ref-parser';
    import { NgOpenApiGen } from 'ng-openapi-gen';
    
    const options = {
      input: "my-api.json",
      output: "my-app/src/app/api",
    }
    
    // load the openapi-spec and resolve all $refs
    const RefParser = new $RefParser();
    const openApi = await RefParser.bundle(options.input, {
      dereference: { circular: false }
    });
    
    const ngOpenGen = new NgOpenApiGen(openApi, options);
    ngOpenGen.generate();
  12. Filter operations and models

    master

    Use tags and paths to include or exclude specific parts of your OpenAPI specification.

    • includeTags: Only include operations with these specific tags.
    • excludeTags: Exclude operations with these specific tags.
    • defaultTag: The tag name assumed for operations without tags. Defaults to the value of prefix (which defaults to 'Api').
    • excludePaths: A list of paths to exclude from processing.
    • ignoreUnusedModels: If true, skips generating models that are not referenced by any operation.
    • excludeParameters: Filters generated services by excluding any parameters matching this list.