Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I reuse Angular 6 API services in a node script?

I would like to reuse some Angular 6 API services in a node script and am facing some troubles initialising everything properly.

The API services are generated using Swagger Codegen (-l typescript-angular), which gives me for example:

@Injectable()
export class UserService {

    constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { 
      ... 
    }

}

These services work perfect in my Angular 6 application and I would now like to use them in a node for some scripting. I'm aware that Swagger Codegen is also able to generate a pure Typescript client, but would still prefer to reuse the existing Angular services to keep the code base more in line.

The challenge I'm then facing is how to call this constructor without dependency injection.

It appears to be very hard to get a valid HttpClient object without dependency injection. In AngularJS I used to rely on Axios for this, but that library does not provide the same interface as HttpClient any more it seems (still promises instead of the newer observables in Angular 6).

It seems to me there would be two options:

  1. Somehow get an HttpClient object -> can't get this to work.
  2. Inject another HTTP client object that exposes the same interface -> can't seem to find one.

Does anybody know how to properly tackle this?

Cheers,

M.

like image 202
DuXati Avatar asked Oct 15 '18 17:10

DuXati


1 Answers

HttpClient isn't supposed to be manually instantiated and this isn't straightforward process because it has a lot of dependencies. Angular injector does all the work on dependency injection and should be used to get an instance.

As shown in this answer, it's possible to get an instance of Angular provider (HttpClient) by setting up a module and bootstrapping it.

A very similar approach should be used for UserService. Here is simplified but workable example:

import 'zone.js/dist/zone-node';
import 'reflect-metadata';

import {Injector, Injectable, NgModule } from '@angular/core'
import {HttpClient, HttpClientModule} from '@angular/common/http'
import {ServerModule, platformDynamicServer} from '@angular/platform-server';

@Injectable()
export class UserService {
  constructor(protected httpClient: HttpClient) { 
    httpClient.get('https://google.com/').subscribe(console.log, console.error);
  }
}

@NgModule({
  imports: [ServerModule, HttpClientModule],
  providers: [UserService]
})
export class AppModule {
  ngDoBootstrap() {}
}

(async () => {
    const platform = platformDynamicServer();
    const appModule = await platform.bootstrapModule(AppModule);
    const userService = appModule.injector.get(UserService);
})()
.catch(console.error);

It needs a compatible TypeScript configuration, e.g.:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "strict": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}
like image 51
Estus Flask Avatar answered Oct 14 '22 23:10

Estus Flask