21

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

pinale
  • 2,060
  • 6
  • 38
  • 72

3 Answers3

18

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
  • 12,569
  • 4
  • 44
  • 42
  • 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
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
  • 2,007
  • 2
  • 17
  • 29
  • 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
  • @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. – Yogurtu Jan 29 '23 at 20:06
  • @Yogurtu yep that was our problem. After awile we changed to generate all services to one file. Then there is only one API_BASE_URL. – Janne Harju Jan 30 '23 at 13:10
4

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
  • 3,428
  • 2
  • 13
  • 15