Skip to content

feat(typescript-angular): add util "provideApi" and update docs to standalone applications #21173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,27 @@ public String getHelp() {
@Override
public void processOpts() {
super.processOpts();

// determine NG version
SemVer ngVersion;
if (additionalProperties.containsKey(NG_VERSION)) {
ngVersion = new SemVer(additionalProperties.get(NG_VERSION).toString());
} else {
ngVersion = new SemVer(this.ngVersion);
LOGGER.info("generating code for Angular {} ...", ngVersion);
LOGGER.info(" (you can select the angular version by setting the additionalProperties (--additional-properties in CLI) ngVersion)");
}
boolean ngVersionAtLeast_17 = ngVersion.atLeast("17.0.0");

supportingFiles.add(
new SupportingFile("models.mustache", modelPackage().replace('.', File.separatorChar), "models.ts"));
supportingFiles
.add(new SupportingFile("apis.mustache", apiPackage().replace('.', File.separatorChar), "api.ts"));
supportingFiles.add(new SupportingFile("index.mustache", getIndexDirectory(), "index.ts"));
supportingFiles.add(new SupportingFile("api.module.mustache", getIndexDirectory(), "api.module.ts"));
if (ngVersionAtLeast_17) {
supportingFiles.add(new SupportingFile("provide-api.mustache", getIndexDirectory(), "provide-api.ts"));
}
supportingFiles.add(new SupportingFile("configuration.mustache", getIndexDirectory(), "configuration.ts"));
supportingFiles.add(new SupportingFile("api.base.service.mustache", getIndexDirectory(), "api.base.service.ts"));
supportingFiles.add(new SupportingFile("variables.mustache", getIndexDirectory(), "variables.ts"));
Expand All @@ -191,16 +206,6 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("README.mustache", getIndexDirectory(), "README.md"));

// determine NG version
SemVer ngVersion;
if (additionalProperties.containsKey(NG_VERSION)) {
ngVersion = new SemVer(additionalProperties.get(NG_VERSION).toString());
} else {
ngVersion = new SemVer(this.ngVersion);
LOGGER.info("generating code for Angular {} ...", ngVersion);
LOGGER.info(" (you can select the angular version by setting the additionalProperties (--additional-properties in CLI) ngVersion)");
}

if (!ngVersion.atLeast("9.0.0")) {
throw new IllegalArgumentException("Invalid ngVersion: " + ngVersion + ". Only Angular v9+ is supported.");
}
Expand Down Expand Up @@ -250,6 +255,7 @@ public void processOpts() {
}

additionalProperties.put(NG_VERSION, ngVersion);
additionalProperties.put("ngVersionAtLeast_17", ngVersionAtLeast_17);

if (additionalProperties.containsKey(API_MODULE_PREFIX)) {
String apiModulePrefix = additionalProperties.get(API_MODULE_PREFIX).toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,157 +58,106 @@ Published packages are not effected by this issue.
In your Angular project:

```typescript
// without configuring providers
import { {{apiModuleClassName}} } from '{{npmName}}';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
imports: [
{{apiModuleClassName}},
// make sure to import the HttpClientModule in the AppModule only,
// see https://github.com/angular/angular/issues/20575
HttpClientModule
],
declarations: [ AppComponent ],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule {}
```

```typescript
// configuring providers
import { {{apiModuleClassName}}, {{configurationClassName}}, {{configurationParametersInterfaceName}} } from '{{npmName}}';

export function apiConfigFactory (): {{configurationClassName}} {
const params: {{configurationParametersInterfaceName}} = {
// set configuration parameters here.
}
return new {{configurationClassName}}(params);
}

@NgModule({
imports: [ {{apiModuleClassName}}.forRoot(apiConfigFactory) ],
declarations: [ AppComponent ],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule {}
```
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
import { provideApi } from '{{npmName}}';

```typescript
// configuring providers with an authentication service that manages your access tokens
import { {{apiModuleClassName}}, {{configurationClassName}} } from '{{npmName}}';

@NgModule({
imports: [ {{apiModuleClassName}} ],
declarations: [ AppComponent ],
export const appConfig: ApplicationConfig = {
providers: [
{
provide: {{configurationClassName}},
useFactory: (authService: AuthService) => new {{configurationClassName}}(
{
basePath: environment.apiUrl,
accessToken: authService.getAccessToken.bind(authService)
}
),
deps: [AuthService],
multi: false
}
// ...
provideHttpClient(),
provideApi()
],
bootstrap: [ AppComponent ]
})
export class AppModule {}
};
```

**NOTE**
If you're still using `AppModule` and haven't [migrated](https://angular.dev/reference/migrations/standalone) yet, you can still import an Angular module:
```typescript
import { DefaultApi } from '{{npmName}}';

export class AppComponent {
constructor(private apiGateway: DefaultApi) { }
}
import { {{apiModuleClassName}} } from '{{npmName}}';
```

Note: The {{apiModuleClassName}} is restricted to being instantiated once app wide.
This is to ensure that all services are treated as singletons.

### Using multiple OpenAPI files / APIs / {{apiModuleClassName}}s

In order to use multiple `{{apiModuleClassName}}s` generated from different OpenAPI files,
you can create an alias name when importing the modules
in order to avoid naming conflicts:
If different from the generated base path, during app bootstrap, you can provide the base path to your service.

```typescript
import { {{apiModuleClassName}} } from 'my-api-path';
import { {{apiModuleClassName}} as OtherApiModule } from 'my-other-api-path';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
imports: [
{{apiModuleClassName}},
OtherApiModule,
// make sure to import the HttpClientModule in the AppModule only,
// see https://github.com/angular/angular/issues/20575
HttpClientModule
]
})
export class AppModule {
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
import { provideApi } from '{{npmName}}';

}
export const appConfig: ApplicationConfig = {
providers: [
// ...
provideHttpClient(),
provideApi('http://localhost:9999')
],
};
```

### Set service base path

If different than the generated base path, during app bootstrap, you can provide the base path to your service.

```typescript
import { BASE_PATH } from '{{npmName}}';
// with a custom configuration
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
import { provideApi } from '{{npmName}}';

bootstrap(AppComponent, [
{ provide: BASE_PATH, useValue: 'https://your-web-service.com' },
]);
export const appConfig: ApplicationConfig = {
providers: [
// ...
provideHttpClient(),
provideApi({
withCredentials: true,
username: 'user',
password: 'password'
})
],
};
```

or

```typescript
import { BASE_PATH } from '{{npmName}}';

@NgModule({
imports: [],
declarations: [ AppComponent ],
providers: [ provide: BASE_PATH, useValue: 'https://your-web-service.com' ],
bootstrap: [ AppComponent ]
})
export class AppModule {}
```

### Using @angular/cli

First extend your `src/environments/*.ts` files by adding the corresponding base path:
// with factory building a custom configuration
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
import { provideApi, {{configurationClassName}} } from '{{npmName}}';

```typescript
export const environment = {
production: false,
API_BASE_PATH: 'http://127.0.0.1:8080'
export const appConfig: ApplicationConfig = {
providers: [
// ...
provideHttpClient(),
{
provide: {{configurationClassName}},
useFactory: (authService: AuthService) => new {{configurationClassName}}({
basePath: 'http://localhost:9999',
withCredentials: true,
username: authService.getUsername(),
password: authService.getPassword(),
}),
deps: [AuthService],
multi: false
}
],
};
```

In the src/app/app.module.ts:
### Using multiple OpenAPI files / APIs

In order to use multiple APIs generated from different OpenAPI files,
you can create an alias name when importing the modules
in order to avoid naming conflicts:

```typescript
import { BASE_PATH } from '{{npmName}}';
import { provideApi as provideUserApi } from 'my-user-api-path';
import { provideApi as provideAdminApi } from 'my-admin-api-path';
import { HttpClientModule } from '@angular/common/http';
import { environment } from '../environments/environment';

@NgModule({
declarations: [
AppComponent
],
imports: [ ],
providers: [{ provide: BASE_PATH, useValue: environment.API_BASE_PATH }],
bootstrap: [ AppComponent ]
})
export class AppModule { }
export const appConfig: ApplicationConfig = {
providers: [
// ...
provideHttpClient(),
provideUserApi(environment.basePath),
provideAdminApi(environment.basePath),
],
};
```

### Customizing path parameter encoding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ export * from './model/models';
export * from './variables';
export * from './configuration';
export * from './api.module';
{{#ngVersionAtLeast_17}}
export * from './provide-api';
{{/ngVersionAtLeast_17}}
export * from './param';
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { makeEnvironmentProviders } from "@angular/core";
import { {{configurationClassName}}, {{configurationParametersInterfaceName}} } from './configuration';
import { BASE_PATH } from './variables';

export function provideApi(configOrBasePath: string | {{configurationParametersInterfaceName}}) {
return makeEnvironmentProviders([
typeof configOrBasePath === "string"
? { provide: BASE_PATH, useValue: configOrBasePath }
: {
provide: {{configurationClassName}},
useValue: new {{configurationClassName}}({ ...configOrBasePath }),
},
]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ model/petWithMappedDiscriminator.ts
model/petWithSimpleDiscriminator.ts
model/petWithoutDiscriminator.ts
param.ts
provide-api.ts
variables.ts
Loading
Loading