how to inject API_BASE_URL (a string) in an angular service
Asked Answered
N

4

22

this autogenerated service (by NSwagStudio) needs an API_BASE_URL (InjectionToken) value in order to perform http requests how and where i can inject it?

/* tslint:disable */
//----------------------
// <auto-generated>
//     Generated using the NSwag toolchain v11.12.16.0 (NJsonSchema v9.10.19.0 (Newtonsoft.Json v9.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------
// ReSharper disable InconsistentNaming

import 'rxjs/add/observable/fromPromise';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/catch';

import { Observable } from 'rxjs/Observable';
import { Injectable, Inject, Optional, InjectionToken } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams, HttpResponse, HttpResponseBase, HttpErrorResponse } from '@angular/common/http';

export const API_BASE_URL = new InjectionToken<string>('API_BASE_URL');

@Injectable()
export class DocumentService {
    private http: HttpClient;
    private baseUrl: string;
    protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;

    constructor(@Inject(HttpClient) http: HttpClient, @Optional() @Inject(API_BASE_URL) baseUrl?: string) {
        this.http = http;
        this.baseUrl = baseUrl ? baseUrl : "";
    }

    getAll(): Observable<string[] | null> {
        let url_ = this.baseUrl + "/api/Document";
        url_ = url_.replace(/[?&]$/, "");

        let options_ : any = {
            observe: "response",
            responseType: "blob",
            headers: new HttpHeaders({
                "Content-Type": "application/json", 
                "Accept": "application/json"
            })
        };

        return this.http.request("get", url_, options_).flatMap((response_ : any) => {
            return this.processGetAll(response_);
        }).catch((response_: any) => {
            if (response_ instanceof HttpResponseBase) {
                try {
                    return this.processGetAll(<any>response_);
                } catch (e) {
                    return <Observable<string[] | null>><any>Observable.throw(e);
                }
            } else
                return <Observable<string[] | null>><any>Observable.throw(response_);
        });
    }

    protected processGetAll(response: HttpResponseBase): Observable<string[] | null> {
        ...........code
        ........
        ....
    }
}

may someone give me some super quick tips about how InjectioToken works and how inject it into this service?

Angular5 - Nswag

Nuclease answered 10/1, 2018 at 7:27 Comment(0)
B
3

To setup and use an injection token, you need to do the following:

  • Create the injection token so it can be consumed (nswag does this for you)
  • Provide the value for the injection token
  • Consume the injection token in your services (e.g. nswag generated client), components, etc.
import { InjectionToken, NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { API_BASE_URL } from 'generated-nswag-client';

export function getBaseUrl() {
    return document.getElementsByTagName('base')[0].href;
}

@NgModule({
    ...,
    providers: [
        { provide: API_BASE_URL, useFactory: getBaseUrl, deps: [] },
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

Now, Nswag and all your components and services, can expect to receive the value corresponding to the token from the dependency-injection system:

@Injectable()
export class MyUrlAwareService {
    apiBaseUrl = inject(API_BASE_URL);
}
Botryoidal answered 19/11, 2023 at 7:33 Comment(0)
M
21

As mentioned above, best is to put this in your environment settings then Angular will replace the appropriate base url depending on the environment you're in, e.g. in dev:

export const environment = {

    production: false,
    apiRoot: "https://localhost:1234",
};

Then you can just use useValue in your provider (everything else removed for simplicity):

...
import { environment } from '@env/environment';

@NgModule({

    imports: [ ... ],

    declarations: [ ... ],

    providers: [

        {
            provide: API_BASE_URL,
            useValue: environment.apiRoot
        },
        ...
    ]

    exports: [ ... ]
})
export class AppModule {}

To use the @env alias as shown above you need to make an addition to the tsconfig.json as follows:

{
    ...
    "compilerOptions": {
        "baseUrl": "src",
        "paths": {
            "@env/*": [ "environments/*" ]
        },
    etc...
}

And Angular will replace the corresponding environment settings depending on the ---env flag used.

Madelene answered 24/11, 2018 at 6:23 Comment(7)
Hi Matt, When I try to implement your code, API_BASE_URL is of course undefined and it's not possible to compile. Where should I import it from? ThanksBaltoslavic
Hi @Nico, have edited my answer to show where this is set up.Madelene
hey Matt, error squiggly showing under '@env/environment' in the import statement in app.module saying Cannot find module '@env/environment'Stig
Hi @Stig - what version of angular are you using?Madelene
@Stig - just tried with ng8 and the above works - you need to make sure the combination of baseUrl and your paths entry in tsconfig points to the environments folder. For example if your baseUrl is "./" then you've used the ng cli to generate your project your paths entry would be "@env/*": [ "src/environments/*" ]Madelene
@Madelene I think what Nico was asking is what should he do because API_BASE_URL is undefined inside of the provide statement. Not about the @env alias.Sanmiguel
Ensure to import API_BASE_URL from the NSwag generated client like import { API_BASE_URL } from 'src/app/services/api.generated.clients'; in the module.ts fileSalicylate
M
15

On the parent module create a provider for API_BASE_URL

export function getBaseUrl(): string {
  return AppConsts.baseUrl;
}

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [{ provide: API_BASE_URL, useFactory: getBaseUrl }],
   bootstrap: [AppComponent]
})
export class AppModule {}

and then define a AppConsts class with static properties as such

export class AppConsts {
  static baseUrl = "your_api_base_url"; 
}

Worked for me, hope it help. This solution is based on aspnet boilerpate angular project, which for me give the best standards on architecture. I leave you here the url for the angular project + the url for this specific code.

Metabolize answered 26/7, 2018 at 15:11 Comment(4)
But if I have several different client files and sevaral API_BASE_URL variables in each files how can I set provider for each of them in one module file. There will be conflict. I tried use 'AP_BASE_URL'. And other thing is there is no need for factory. You can use useValue instead of factory. Then you can set value directly from environment or as you use AppConstsUndenominational
And how do you write a test for components that have a @injector in the constructor like OP's DocumentServiceDisconcerted
@JanneHarju if you have more than one service, just create different API_BASE_URL_Client1, API_BASE_URL_Client2... of course this is kind of painful, because if you regenerate the client, it will be lost, and you'll need to update it manually. nswag is not really prepared to use more than one client, so it's a small price.Cornett
@Cornett yep that was our problem. After awile we changed to generate all services to one file. Then there is only one API_BASE_URL.Undenominational
D
4

The best practice is to put all constants in environment.ts and environment.prod.ts. Just create a new property there and import it into your service. Your code will look like this:

// environment.ts
export const environment = {
  production: false,
  API_BASE_URL: "baseUrlOfApiForDevelopment",
};

// environment.prod.ts
export const environment = {
  production: false,
  API_BASE_URL: "baseUrlOfApiForProduction",
};

Now all you need to do is import this into your service and use it.

Dreary answered 10/1, 2018 at 7:33 Comment(1)
This defeats the purpose of using NSWAG to auto generate the service fileBackup
B
3

To setup and use an injection token, you need to do the following:

  • Create the injection token so it can be consumed (nswag does this for you)
  • Provide the value for the injection token
  • Consume the injection token in your services (e.g. nswag generated client), components, etc.
import { InjectionToken, NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { API_BASE_URL } from 'generated-nswag-client';

export function getBaseUrl() {
    return document.getElementsByTagName('base')[0].href;
}

@NgModule({
    ...,
    providers: [
        { provide: API_BASE_URL, useFactory: getBaseUrl, deps: [] },
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

Now, Nswag and all your components and services, can expect to receive the value corresponding to the token from the dependency-injection system:

@Injectable()
export class MyUrlAwareService {
    apiBaseUrl = inject(API_BASE_URL);
}
Botryoidal answered 19/11, 2023 at 7:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.