15

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

alex
  • 1,304
  • 3
  • 22
  • 50

3 Answers3

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.

Guido Dizioli
  • 1,047
  • 2
  • 14
  • 25
  • 1
    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 AppConsts – Janne Harju Feb 10 '19 at 11:03
  • And how do you write a test for components that have a @injector in the constructor like OP's DocumentService – GregJF Mar 19 '19 at 05:01
13

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.

Matt
  • 9,685
  • 4
  • 37
  • 36
  • 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? Thanks – Nico Feb 24 '19 at 17:01
  • 1
    Hi @Nico, have edited my answer to show where this is set up. – Matt Feb 24 '19 at 21:33
  • hey Matt, error squiggly showing under `'@env/environment'` in the import statement in app.module saying `Cannot find module '@env/environment'` – atiyar Aug 23 '19 at 16:11
  • Hi @atiyar - what version of angular are you using? – Matt Aug 29 '19 at 10:47
  • 1
    @atiyar - 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/*" ] – Matt Aug 31 '19 at 06:12
  • @Matt 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. – El Mac Sep 24 '20 at 08:04
  • 1
    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 file – Nadeem Yousuf-AIS Oct 02 '20 at 02:34
3

THe best practice to put all constants in environment.ts and environment.prod.ts. Just create a new property their and import in 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 you need to import in your service to use it.

Sandip Jaiswal
  • 2,340
  • 1
  • 11
  • 13