0

I tried to create a generic service to call my API and build is giving me that error :

Can't resolve all parameters for DataService in /ng-app/src/app/services/data.service.ts: (?, [object Object]).

I know i'm not the first who got it but everything I found didn't help.

Here is what i tried :

  • Checking if @Injectable was correct
  • Not using the barrel
  • Using types in constructor params
  • Tsconfig.json emitDecoratorMetadata set to true
  • All services are registered in the Providers part of the ngModule

I don't know what else I could try to fix it ...

Here is some code :

DataService :

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { catchError } from 'rxjs/operators';

import { Observable } from 'rxjs';
import { AppError } from '../common/validators/app-error';
import { NotFoundError } from '../common/not-found-error';
import { BadRequest } from './../common/bad-request-error';

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

  constructor(private url: string, public httpClient: HttpClient) { }

  getAll(){
    return this.httpClient.get(this.url).pipe(catchError(this.handleError));
  }

  getOne(ressource){
    return this.httpClient.get(this.url + '/' + ressource).pipe(catchError(this.handleError));
  }

  create(ressource){
    return this.httpClient.post(this.url, JSON.stringify(ressource)).pipe(catchError(this.handleError));
  }

  update(ressource,oldRessource){
    return this.httpClient.put(this.url + '/' + oldRessource, JSON.stringify(ressource)).pipe(catchError(this.handleError));
  }

  delete(ressource){
    return this.httpClient.delete(this.url + '/' + ressource).pipe(catchError(this.handleError));
  }

  public handleError(err: Response){
    if (err.status == 400 ){
      return Observable.throw(new BadRequest(err));
    }

    if (err.status == 404) {
      return Observable.throw(new NotFoundError());
    }
    // Return error by default if no specific error
    return Observable.throw(new AppError(err));
  }
}

A service extending from DataService

import { HttpClient } from '@angular/common/http';
import { DataService } from './data.service';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class CategorieService extends DataService {

  constructor(httpClient: HttpClient) { 

    super('http://localhost:8081/categories' ,httpClient);

  }
}

UPDATE:

I got I have to use a ToketInjection pattern to solve my issue. I also used environments classes to avoid having to setup the base URL at different places.

But I still don't get how i can now change that URL in my DataService for each Services extending from DataService.

Here is some code :

App.module.ts :

...

import { CategorieService } from './services/categorie.service';
import { DataService } from './services/data.service';
import { environment } from 'src/environments/environment';


export function getBaseUrl(): string {
  return environment.API_BASE_URL;
}

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
    ])
  ],
  providers: [
    ...
    DataService,
    CategorieService,
    { provide: 'API_BASE_URL', useFactory: getBaseUrl },
  ],
  bootstrap: [AppComponent]
})

export class AppModule { }

Environement.ts

export const environment = {
  production: false,
  API_BASE_URL: "http://localhost:8081/",
};

Data.service.ts

import { Injectable, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { catchError } from 'rxjs/operators';

import { Observable } from 'rxjs';
import { AppError } from '../common/validators/app-error';
import { NotFoundError } from '../common/not-found-error';
import { BadRequest } from './../common/bad-request-error';

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

  //constructor(private url: string, public httpClient: HttpClient) { }
  constructor(@Inject('API_BASE_URL') private url, public httpClient: HttpClient) { }

  getAll(){
    return this.httpClient.get(this.url).pipe(catchError(this.handleError));
  }

  getOne(ressource){
    return this.httpClient.get(this.url + '/' + ressource).pipe(catchError(this.handleError));
  }

  create(ressource){
    return this.httpClient.post(this.url, JSON.stringify(ressource)).pipe(catchError(this.handleError));
  }

  update(ressource,oldRessource){
    return this.httpClient.put(this.url + '/' + oldRessource, JSON.stringify(ressource)).pipe(catchError(this.handleError));
  }

  delete(ressource){
    return this.httpClient.delete(this.url + '/' + ressource).pipe(catchError(this.handleError));
  }

  public handleError(err: Response){
    if (err.status == 400 ){
      return Observable.throw(new BadRequest(err));
    }

    if (err.status == 404) {
      return Observable.throw(new NotFoundError());
    }
    // Return error by default if no specific error
    return Observable.throw(new AppError(err));
  }
}

I would like to add some parameters to my base API URL the same way i tried to do it before to be able to reach specific parts of my API but i don't get how to do that with TokenInjection.

Ishiru
  • 127
  • 1
  • 16

1 Answers1

1

You don't really wanna put a string in your constructor. You could do something like an injection token or putting that string as a const in your environments file and then importing your environments as as a provider like they did here.

QT Ray
  • 1,256
  • 8
  • 12
  • Thanks, I'll try this and keep you updated. I foud an easy to follow tutorial here : https://medium.com/coding-blocks/power-of-angular-dependency-injection-b981faa9c0de :) – Ishiru Aug 29 '19 at 02:33
  • I did read about it and there is still something i don't get. How can i pass this token from my service extending from my DataService to my DataService ? – Ishiru Aug 29 '19 at 04:17
  • @Ishiru can you update your original question to see how you're using the injectionToken? – QT Ray Aug 29 '19 at 15:43
  • I did provide an update, you can see i also used Environement classes to setup the base URL – Ishiru Aug 29 '19 at 18:13