1

I am trying to generate an API client from a v2 swagger file with openapi-generator-cli. For this I am using the docker container of openapi-generator-cli, which reports its version as '4.1.0-SNAPSHOT'.

Code generation works with the following options:

{
    "npmName": "...",
    "npmVersion": "0.0.3",
    "snapshot": true,
    "ngVersion": "8.1.1"
}

and I have also tried to set the providedInRoot option to true.

However, the generated service classes are not annotated with the @Injectable decorator. So after importing them in my component and adding the service in the constructor of the component, I am not able to use them. This is how my component looks like:

import { Component, OnInit } from '@angular/core';

import { UsersService, User } from '...'

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  constructor(userService: UsersService) {}

  title = 'user-frontend';

  ngOnInit() {
    this.userService.listUsers();
  }

}

which fails, because userService does not exist in the scope of AppComponent.

This is how I import the generated module:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

import { ApiModule } from '...';
import { HttpClientModule } from '@angular/common/http';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ApiModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Any ideas on where my error is when generating the api client?

EDIT: The generated code looks like this:

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

    protected basePath = 'http://localhost';
    public defaultHeaders = new HttpHeaders();
    public configuration = new Configuration();
    public encoder: HttpParameterCodec;

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

        if (configuration) {
            this.configuration = configuration;
            this.configuration.basePath = configuration.basePath || basePath || this.basePath;

        } else {
            this.configuration.basePath = basePath || this.basePath;
        }
        this.encoder = this.configuration.encoder || new CustomHttpParameterCodec();
    }

...
}
der_berni
  • 58
  • 9

1 Answers1

4

Alot of questions import { ApiModule } from '...'; where is code generated come from ? You publish it to npm and consume it or just copy paste the generated code? Try this

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    ApiModule.forRoot(() => {
      return new Configuration({
        basePath: `${environment.HOST}:${environment.PORT}`,
      });
    }),,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Your generated code should like this

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

    protected basePath = 'http://localhost';
    public defaultHeaders = new HttpHeaders();
    public configuration = new Configuration();

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

        if (configuration) {
            this.configuration = configuration;
            this.configuration.basePath = configuration.basePath || basePath || this.basePath;

        } else {
            this.configuration.basePath = basePath || this.basePath;
        }
    }

Solution : use private or public in the constructor

Explanation: Here we have the same as your problem typescript dont know what you want

class TestClass {
  constructor(name: string) {
  }
}

Here we have last example in a normal POO promamming language

class TestClass {
  private name: string;

  constructor(name: string) {
    this.name = name;
  }
}

But typescript give us a easy way to minimize the code

class TestClass {
  constructor(private name: string) { }
}
anthony willis muñoz
  • 2,346
  • 3
  • 16
  • 33
  • Thanks for the tip, unfortunately I still get the same error. To answer your question, I publish the generated code to a private npm und consume it from there. Since I can import the ApiModule, classes and so on, I am quite confident that this part works. Could you hint at why the different ways of bringing the ApiModule into my project could lead to such an error? – der_berni Jul 30 '19 at 08:14
  • You generate the code and convert it to a angular library with ng-packagr? – anthony willis muñoz Jul 30 '19 at 08:29
  • Exactly, I generate the code, switch to the folder with the generated code, then I run: ```npm``` install, next ```npm run build``` (which executes ng-packagr), then I log in to my npm registry and do a ```npm publish dist``` to my registry. – der_berni Jul 30 '19 at 08:47
  • I got the same so seems like is a template issue check my edit above and tell me if you generate code its something like that – anthony willis muñoz Jul 30 '19 at 08:51
  • Thanks for your help, I edited my question and appended the exported UsersService class. Looks the same for me. – der_berni Jul 30 '19 at 08:58
  • its weird, after work I will help you more. There are some error or just not recognize the service ? – anthony willis muñoz Jul 30 '19 at 09:45
  • With the code above I get the following error when building the angular project: Property 'userService' does not exist on type 'AppComponent'. – der_berni Jul 30 '19 at 10:59
  • try private userService: UsersService – anthony willis muñoz Jul 30 '19 at 11:02
  • Thanks, I also just tried that, and now it works... Do you have an explanation why a private/public keyword is necessary? Is there no defaulting to private for example? – der_berni Jul 30 '19 at 11:10
  • the explanation is above :) – anthony willis muñoz Jul 30 '19 at 11:22