Nswag: How to inject configuration, like auth bearer token header, into BaseClass in TypeScript client

Created on 4 Aug 2018  路  8Comments  路  Source: RicoSuter/NSwag

I am using the SwaggerToTypeScriptClient to generate a Javascript/TypeScript client SDK that should be framework and platform agnostic. As others mentioned (#512 + #643 and others), I'm struggling with the problem of being able to inject an authorization bearer token in the header, from the consuming perspective.

I know the formal response is "add a header in transformOptions", but I can't see this working with my solution. For example, I am able to generate a BaseClass which neatly acts as a super class for all api clients:

export class ApiClientBase {
    protected transformOptions(options: RequestInit): Promise<RequestInit> {
        options.headers = { ...options.headers, authorization: ' bearer ' + '???' };
        return Promise.resolve(options);
    }

    protected transformResult(url: string, response: Response, processor: (response: Response) => any) {
        return processor(response);
    }
}

As you can see in the above code, the '???' is the problematic part leading to the question:

How can I inject this from my client?

Considering I have a (vanilla) client, I cannot resolve to:

  • Adding a constructor with a 'token' parameter to the base class. This breaks all api clients.
  • Having a service locator in the (parameterless) constructor, because that requires a framework specific implementation
  • Reverting to for example localStorage, because the consumer might not even be browser-based

Just for the sake of completeness, here is something I'm trying to achieve from a consumer perspective:

test.only('do a call, requiring authentication', async () => {
    const token = 'abc123';

    const api = new TimeApiClient('http://localhost:5000');
    const target = await api.time();

    // ^ fails, because I can't 'inject' the token anywhere nor can I access the ApiClientBase
});

To summarize, what I think I'm looing for is either :

  1. Being able to pass the token as argument to either the TimeApiClient or to the time() operation on it.
  2. Being able to define a reusable fetch client, or override the fetch parameter in the time() operation, but I'm not quite seeing how I could do this.

Is there a way to do this?
Thanks.

Most helpful comment

It would be awesome if you could improve the wiki so that all this is more discoverable...

All 8 comments

Also, please be aware that it's properly outputted in the swagger.json file:

"securityDefinitions": {
    "Bearer": {
    "name": "Authorization",
    "in": "header",
    "type": "apiKey",
    "description": ""
}

Other tools like Swagger UI and swagger-codegen respect it, so I'm also wondering if this might be a third option?

For example, swagger-codegen allows me to inject a config (also autogenerated) like this:

test.only('do a call, requiring authentication', async () => {
    const config: Configuration = {
        accessToken: 'ABC123',
        basePath: 'http://localhost:5000'
    };

    const api = new TimeApi(config);
    const target = await api.timeGet();
});

I think with the ConfigurationClass setting you can define a class which gets injected and can be used in the base class? Or is this c# only?

This... is awesome. Wasn't aware of the ConfigurationClass being available, but indeed by simply setting:

"configurationClass": "MyConfig",
"extensionCode": "src/ApiClientBase.ts",

and adding the MyConfig class to the ApiClientBase.ts this allows it to be injectable in the constructor (and base class). The Picturepark sample helped.

@RSuter thanks a bunch, really!

It would be awesome if you could improve the wiki so that all this is more discoverable...

@RicoSuter Thanks for the hints, I added a section detailing your suggestion!
https://github.com/RicoSuter/NSwag/wiki/TypeScriptClientGenerator#inject-an-authorization-header

The only -- small -- remaining problem is that the provided file gets appended to the end of the generated file, thus I get the following error

Class 'AuthorizedApiBase' used before its declaration.ts(2449)
api.generated.clients.ts(10765, 7): 'AuthorizedApiBase' is declared here.

It seems extension code may not be the correct way to do it?
Is there an alternative?

@RicoSuter Thanks for the hints, I added a section detailing your suggestion!
https://github.com/RicoSuter/NSwag/wiki/TypeScriptClientGenerator#inject-an-authorization-header

The only -- small -- remaining problem is that the provided file gets appended to the end of the generated file, thus I get the following error

Class 'AuthorizedApiBase' used before its declaration.ts(2449)
api.generated.clients.ts(10765, 7): 'AuthorizedApiBase' is declared here.

It seems extension code may not be the correct way to do it?
Is there an alternative?

It's a problem with the comments as seen here https://github.com/RicoSuter/NJsonSchema/issues/779

Just remove the comments and you are good to go :)

worked like a charm!
you can also rewrite the comment to remove the word "class", e.g. use "clazz" or "c l a s s"

thanks again!

Was this page helpful?
0 / 5 - 0 ratings