30

I followed the official tutorials and made services for the Apis but absolute url of the Api is hardcoded in services.

I want to keep the base url of Api somewhere so that i can append it to the url path in each service before call. i also need to change the base url of Api before building (or after building).

i tried to put it in sessionstorage, but that is a bad idea as anyone can change it and my application will start hitting other domain.

so i kept it hard-coded and placed a post-push hook on the git to replace the url after build. but it is more like a hack than a solution.

Can i place a file in the root directory of angular and put Api url in json format . And include it in each service so that i can exclude the file from git and each teammate and the build server can have their own file having different url.

What should be the recommended way of doing it?

1

6 Answers 6

29

After release of Angular 4.3 we have a possibility to use HttpClient interceprtors. The advantage of this method is avoiding of import/injection of API_URL is all services with api calls.

This is my basic implementation:

@Injectable()
export class ApiUrlInterceptor implements HttpInterceptor {
constructor(@Inject(API_URL) private apiUrl: string) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    req = req.clone({url: this.prepareUrl(req.url)});
    return next.handle(req);
  }

  private isAbsoluteUrl(url: string): boolean {
    const absolutePattern = /^https?:\/\//i;
    return absolutePattern.test(url);
  }

  private prepareUrl(url: string): string {
    url = this.isAbsoluteUrl(url) ? url : this.apiUrl + '/' + url;
    return url.replace(/([^:]\/)\/+/g, '$1');
  }
}

InjectionToken declaration:

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

Provider registration:

{provide: API_URL, useValue: environment.apiUrl}
{provide: HTTP_INTERCEPTORS, useClass: ApiUrlInterceptor, multi: true, deps: [API_URL]}

Environment.ts:

export const environment = {
 production: false,
 apiUrl: 'some-dev-api'
};
Sign up to request clarification or add additional context in comments.

10 Comments

this looks good . even i was searching for HttpClient interceptors but can u elaborate on things like where should the code for "Injection Token declaration" and "Provider registration" be placed
Not sure about this right now. Ihe placed this code in app.module.ts. Ill check if this decision is scalable enough and leave a comment here later.
Where do you put the Injection Token declaration?
@redOctober13 Yes, you can just import the api url from environment file. Injection token just serve for your convenience. They give you an opportunity to make your modules configurable. This will be useful, if you develop some sharable module (with this interceptor) between several application (maybe community also), as they can have different api urls. Injection token helped me to write the unit test also. I made {provide: API_URL, useValue: 'http://example.com'} in my spec file to make it not dependent from my environment.
@redOctober13 In your barrel file, you import API_URL: import {API_URL, ApiUrlInterceptor} from './api-url.interceptor'; The "InjectionToken declaration" is in the ApiUrlInterceptor file. And this is what your barrel http interceptor file should look like : /** "Barrel" of Http Interceptors */ import ... ; /** Http interceptor providers in outside-in order */ export const httpInterceptorProviders = [ {provide: API_URL, useValue: environment.apiUrl}, {provide: HTTP_INTERCEPTORS, useClass: ApiUrlInterceptor, multi: true, deps: [environment.apiUrl]}, ];
|
7

Use the environment files

If youre using the cli you should use the environment files. By configuring the angular-cli.json file you can manage all the available environments and create new ones. For example you could create an environment.dev.js file and store the values there, by making git ignore it any member in your team can have a customized one.

Said environment file will overwrite the original environment.js

See this SO answer angular-cli for angular2 how to load environment variables

Comments

5

Usually I put these in the const environment file. If you are using angular-cli, this is already provided for you if not you can create your own:

export const environment = {  
  production: false,
  api: 'http://localhost:4200/api/'
};

You can have multiple environment file, like environment.production.ts, then with angular-cli you would run:

ng build --environment=production

If you are not using angular-cli, pretty sure you can build your own something similar.

2 Comments

@ScottMoniz just environment.api. Just make sure you import it first
Yep - figured it out :) Working well! Happy Holidays to you!
0
export class AppSettings {
   public static API_ENDPOINT='http://127.0.0.1:6666/api/';
}

And then in the service:

import {Http} from 'angular2/http';
import {Message} from '../models/message';
import {Injectable} from 'angular2/core';
import {Observable} from 'rxjs/Observable';
import {AppSettings} from '../appSettings';
import 'rxjs/add/operator/map';

@Injectable()
export class MessageService {

    constructor(private http: Http) { }

    getMessages(): Observable<Message[]> {
        return this.http.get(AppSettings.API_ENDPOINT+'/messages')
            .map(response => response.json())
            .map((messages: Object[]) => {
                return messages.map(message => this.parseData(message));
            });
    }

    private parseData(data): Message {
        return new Message(data);
    }
}

Comments

-1

In app module add window object

import {provide} from 'angular2/core';
bootstrap([provide(Window, {useValue: window})]);

After that you can access window in controller

constructor(private window: Window) {
 var hostname = this.window.location.hostname;
}

There is no angular 2 specific solution.In angularJS(version 1) we use $location service

$location.protocol() + "://" + $location.host() + ":" + $location.port();

Comments

-2

You can create an Interceptor to add the base API URL

@Injectable()
export class CustomHttpInterceptor implements HttpInterceptor {

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log('Custom Interceptor');

    // Adding serverHostURL to all APIs in Interceptor
    const serverHostURL = 'http://localhost:8080';
    request = request.clone({
      url: serverHostURL + request.url
    });


    return next.handle(request);
  }

Above code should do.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.