Dynamically Configuring the Swagger-Generated API Base Path in Angular
When working with APIs in Angular, we often use tools like Swagger Codegen or OpenAPI Generator to generate TypeScript clients. However, these generated clients typically include a hardcoded basePath, making it difficult to dynamically configure environments. In this article, we’ll explore how to inject the basePath dynamically without modifying the generated files. We'll also ensure that it works seamlessly in both NgModules and Standalone Components. The Problem: Hardcoded Base Path in Generated Code By default, Swagger-generated clients often include something like: protected basePath = 'https://{INSTANCE_NAME}.example.com/api/2.0'; Here, {INSTANCE_NAME} is a plain string, not a variable that can be injected dynamically. This means that every time we need to change the API endpoint, we would have to modify the generated code manually. This is not scalable, especially when dealing with multiple APIs. The Solution: Use a Configuration Provider in the Module Step 1: Leverage the Configuration Class Luckily, the generated code includes a Configuration class: export class Configuration { basePath?: string; constructor(configurationParameters: ConfigurationParameters = {}) { this.basePath = configurationParameters.basePath; } } This means we can provide a Configuration instance dynamically instead of modifying the generated files. Step 2: Create a Factory Function for Configuration To inject the base path dynamically, create a configuration factory function: import { Configuration } from './generated/configuration'; // Adjust the import path export function configurationFactory(): Configuration { return new Configuration({ basePath: `https://mysite.example.com/api/2.0` }); } This function returns a Configuration instance with the dynamically set basePath. Step 3: Provide Configuration in the AppModule Now, in the root module, we use ApiModule.forRoot() and pass in our configuration 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 ensures that every API service in our project gets the dynamically provided basePath. Using the API in a Standalone Component If you’re using standalone components, you don’t need forRoot(). Simply 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: `Standalone Component` }) export class StandaloneComponent { constructor(private apiService: SomeApiService) { this.apiService.someApiMethod().subscribe(response => { console.log(response); }); } } Since the Configuration is already provided in the module, the API services work without any extra setup. Why This Approach Works ✅ No modifications to generated files ✅ Centralized configuration in AppModule ✅ Works with both NgModules and Standalone Components ✅ Scales easily for multiple APIs By leveraging Angular’s dependency injection and ApiModule.forRoot(), we ensure that our API clients are configurable, maintainable, and work seamlessly across the app. Conclusion If you're using Swagger Codegen in an Angular project, don’t modify the generated files manually. Instead, use ApiModule.forRoot() and inject a Configuration object dynamically. This approach makes your API clients environment-independent, scalable, and easy to maintain. Let me know your thoughts! Have you faced similar challenges when integrating Swagger APIs into Angular?

When working with APIs in Angular, we often use tools like Swagger Codegen or OpenAPI Generator to generate TypeScript clients. However, these generated clients typically include a hardcoded basePath
, making it difficult to dynamically configure environments.
In this article, we’ll explore how to inject the basePath
dynamically without modifying the generated files. We'll also ensure that it works seamlessly in both NgModules and Standalone Components.
The Problem: Hardcoded Base Path in Generated Code
By default, Swagger-generated clients often include something like:
protected basePath = 'https://{INSTANCE_NAME}.example.com/api/2.0';
Here, {INSTANCE_NAME}
is a plain string, not a variable that can be injected dynamically. This means that every time we need to change the API endpoint, we would have to modify the generated code manually.
This is not scalable, especially when dealing with multiple APIs.
The Solution: Use a Configuration Provider in the Module
Step 1: Leverage the Configuration
Class
Luckily, the generated code includes a Configuration
class:
export class Configuration {
basePath?: string;
constructor(configurationParameters: ConfigurationParameters = {}) {
this.basePath = configurationParameters.basePath;
}
}
This means we can provide a Configuration
instance dynamically instead of modifying the generated files.
Step 2: Create a Factory Function for Configuration
To inject the base path dynamically, create a configuration factory function:
import { Configuration } from './generated/configuration'; // Adjust the import path
export function configurationFactory(): Configuration {
return new Configuration({
basePath: `https://mysite.example.com/api/2.0`
});
}
This function returns a Configuration
instance with the dynamically set basePath
.
Step 3: Provide Configuration in the AppModule
Now, in the root module, we use ApiModule.forRoot()
and pass in our configuration 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 ensures that every API service in our project gets the dynamically provided basePath
.
Using the API in a Standalone Component
If you’re using standalone components, you don’t need forRoot()
. Simply 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: `Standalone Component`
})
export class StandaloneComponent {
constructor(private apiService: SomeApiService) {
this.apiService.someApiMethod().subscribe(response => {
console.log(response);
});
}
}
Since the Configuration
is already provided in the module, the API services work without any extra setup.
Why This Approach Works
✅ No modifications to generated files
✅ Centralized configuration in AppModule
✅ Works with both NgModules and Standalone Components
✅ Scales easily for multiple APIs
By leveraging Angular’s dependency injection and ApiModule.forRoot()
, we ensure that our API clients are configurable, maintainable, and work seamlessly across the app.
Conclusion
If you're using Swagger Codegen in an Angular project, don’t modify the generated files manually. Instead, use ApiModule.forRoot()
and inject a Configuration
object dynamically.
This approach makes your API clients environment-independent, scalable, and easy to maintain.
Let me know your thoughts! Have you faced similar challenges when integrating Swagger APIs into Angular?