Angular Rest API generic service and implementation service I'm wondering if there's a better way to write the ApiService and the CategoryService so that CategoryService is basically just a call to extend ApiService with the string 'category' and the base type 'ICategory' or if this is the best that I can get from typescript and angular? There will be many more endpoint services in the final app

Any other general comments on code style etc are also very welcome (or if anyone knows how to tell Webstorm to not put the constructor closing braces on the next line!!)

ApiService

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../../environments/environment';

const baseUrl = environment.serverBaseUrl;
const apiEndpoint = environment.apiEndpoint || '/api/v1/';
const apiUrl = `${baseUrl}${apiEndpoint}`;

@Injectable({
  providedIn: 'root'
})
export class ApiService {

  constructor(private http: HttpClient) {
  }

  private createTokenOptions() {
    return {headers: new HttpHeaders().set('Authorization', `Bearer ${localStorage.getItem('access_token')}`)};
  }

  get&lt;T&gt;(serviceEndpoint: string, id?: number): Observable&lt;T&gt; {
    let url = `${apiUrl}${serviceEndpoint}`;
    if (id) {
      url += `/${id}`;
    }
    return this.http.get&lt;T&gt;(url, this.createTokenOptions());
  }

  create&lt;T&gt;(serviceEndpoint, item: T): Observable&lt;object&gt; {
    const options = this.createTokenOptions();
    options.headers = options.headers.append('Content-Type', 'application/json');
    return this.http.post(`${apiUrl}${serviceEndpoint}`, JSON.stringify(item), options);
  }

  delete&lt;T&gt;(serviceEndpoint: string, id: number): Observable&lt;T&gt; {
    return this.http.delete&lt;T&gt;(`${apiUrl}${serviceEndpoint}/${id}`, this.createTokenOptions());
  }
}


CategoryService

import { Injectable } from '@angular/core';
import { ApiService } from './api.service';
import { Observable } from 'rxjs';
import { ICategory } from '../interfaces/category.model';


@Injectable({
  providedIn: 'root'
})
export class CategoryService {

  private serviceEndpoint = 'category';

  constructor(private api: ApiService) {
  }

  getCategories() {
    return this.api.get&lt;ICategory[]&gt;(this.serviceEndpoint);
  }

  getCategory(id: number): Observable&lt;ICategory&gt; {
    return this.api.get&lt;ICategory&gt;(this.serviceEndpoint, id);
  }

  createCategory(category: ICategory) {
    return this.api.create&lt;ICategory&gt;(this.serviceEndpoint, category);
  }

  deleteCategory(id: number) {
    return this.api.delete&lt;ICategory&gt;(this.serviceEndpoint, id);
  }
}
I think you can use HTTP Interceptors to simplify the code.

For the authorization

@Injectable()
export class AuthorizationInterceptor implements HttpInterceptor {

  constructor() {
  }

  intercept(request: HttpRequest&lt;any&gt;, next: HttpHandler): Observable&lt;HttpEvent&lt;any&gt;&gt; {

    // skip requests for local assets
    if (request.url.indexOf("assets/") &gt;= 0) {
      return next.handle(request);
    }

    const apiReq = request.clone({
      url: request.url,
      headers: request.headers.set('Authorization', `Bearer ${localStorage.getItem('access_token')}`)
    });
    return next.handle(apiReq);
  }
}


For the base url

Something along the line

@Injectable()
export class BaseUrlInterceptor implements HttpInterceptor {

  constructor(
    @Inject("BASE_API_URL") private baseUrl: string) {
  }

  intercept(request: HttpRequest&lt;any&gt;, next: HttpHandler): Observable&lt;HttpEvent&lt;any&gt;&gt; {

    // skip requests for local assets
    // maybe put extra condition to allow for multiple API usage
    if (request.url.indexOf("assets/") &gt;= 0) {
      return next.handle(request);
    }

    const apiReq = request.clone({
      url: `${this.baseUrl}${request.url}`
    });
    return next.handle(apiReq);
  }
}


Of course, the module should define the interceptors:

  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthorizationInterceptor,
      multi: true
    }
  ]