The Challenge: Fixed Base URLs in Auto-Generated API Code
When integrating APIs into Angular applications, developers frequently rely on generators such as Swagger Codegen or OpenAPI Generator to produce TypeScript clients. A common limitation of these generated artifacts is that they ship with a static basePath, which complicates environment-specific configuration.
This guide demonstrates how to inject the basePath at runtime while leaving the generated code untouched. The solution is designed to function across both NgModules and Standalone Components.
The Issue: Static Paths Inside Generated Output
Typical Swagger-generated clients contain a hardcoded value similar to:
protected basePath = 'https://{INSTANCE_NAME}.example.com/api/2.0';
In this snippet, {INSTANCE_NAME} is a fixed string literal, not a placeholder that can be resolved through dependency injection. As a result, changing the target endpoint forces you to manually edit the generated files.
This becomes unmanageable, particularly in projects that consume numerous API services.
The Fix: Registering a Configuration Provider
Step 1: Utilize the Configuration Class
Fortunately, the code generator includes a Configuration class:
export class Configuration {
basePath?: string;
constructor(configurationParameters: ConfigurationParameters = {}) {
this.basePath = configurationParameters.basePath;
}
}
This presence allows you to register a Configuration object at runtime, sidestepping any need to alter the generated output.
Step 2: Build a Configuration Factory
To make the base path configurable, define a factory function that produces the configuration object:
import { Configuration } from './generated/configuration'; // Adjust the import path
export function configurationFactory(): Configuration {
return new Configuration({
basePath: `https://mysite.example.com/api/2.0`
});
}
The returned Configuration instance carries the basePath that has been resolved from the current environment.
Step 3: Register the Configuration in AppModule
At the application root, invoke ApiModule.forRoot() and pass in the factory:
import { NgModule } from '@angular/core';
import { ApiModule } from './generated/api.module'; // Adjust the import path
import { configurationFactory } from './configuration.factory'; // Import our factory function
@NgModule({
imports: [
ApiModule.forRoot(configurationFactory) // Provide the API configuration
],
bootstrap: [AppComponent] // Root component
})
export class AppModule { }
This setup guarantees that every API service throughout the application receives the correct basePath from the provider.
Consuming the API in a Standalone Component
For projects using standalone components, forRoot() is unnecessary. Just import ApiModule directly:
import { Component } from '@angular/core';
import { ApiModule } from './generated/api.module'; // Import the API module
import { SomeApiService } from './generated/api/some-api.service'; // Example API service
@Component({
selector: 'app-standalone',
standalone: true,
imports: [ApiModule], // No need for forRoot()
template: `<p>Standalone Component</p>`
})
export class StandaloneComponent {
constructor(private apiService: SomeApiService) {
this.apiService.someApiMethod().subscribe(response => {
console.log(response);
});
}
}
Because the Configuration is already available at the module level, API services function without any additional wiring.
Why This Strategy Is Effective
✅ Generated files remain untouched
✅ All configuration is centralized within AppModule
✅ Compatible with NgModules and Standalone Components
✅ Simplifies adding multiple API integrations
By taking advantage of Angular's dependency injection system alongside ApiModule.forRoot(), the API clients become flexible, easy to maintain, and consistent across the entire application.
Final Thoughts
When working with Swagger Codegen in an Angular context, avoid manual edits to generated files. Instead, rely on ApiModule.forRoot() and provide a dynamic Configuration object.
The outcome is an API layer that is environment-agnostic, easy to scale, and straightforward to maintain.
Share your experiences! Have you encountered similar hurdles while integrating Swagger APIs into your Angular projects? 🚀
