Hello,
My problem is linked to this issue #512
How do I implement the transform option for typescript for angular2. It seems to be different from angular 1 since we are using Observable. In the generated service I got this
return Observable.fromPromise(this.transformOptions(options_)).concatMap(transformedOptions_ => {;
so I assume that the function is expecting a promise.
This is the transformOptions method of my base class.
` protected transformOptions(options: any) {
options.headers.Authorization = 'Bearer ' + localStorage.getItem(Const.authData.token);
var promise = new Promise(function (resolve, reject) {
resolve(options);
});
return promise;
}`
But it doesn't work. The bearer token are not passed to the http request.
When I inspect the final transformation, my headers is not the same as the one added per default.

My guess is that the headers are also observables and i'm not adding the authorization header correctly.
What is the best way please?
Hi @paddyfink
The way I did it was to create a baseclient.ts, with the following contents:
import { OAuthService } from 'angular-oauth2-oidc';
import globals = require('../app/globals');
class BaseClient {
private oAuthService: OAuthService;
constructor() {
this.oAuthService = globals.injector.get(OAuthService);
}
transformOptions(options: RequestOptionsArgs): RequestOptionsArgs {
options.headers = new Headers({
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': this.oAuthService.authorizationHeader(),
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
});
return options;
}
}
Then, reference this baseclient.ts in your swagger command, with: nswag swagger2tsclient /input:[yourSwaggerJson] /output:.[...]/apiclient.ts /template:angular2 /ClientBaseClass:BaseClient /ExtensionCode:[...]/baseclient.ts /UseTransformOptionsMethod:true
You should then find that your generated clients all extend the BaseClient class, and so will get their headers updated accordingly when you make an HTTP request.
Obviously in my example the authorization header is coming from the injector, whereas yours will be coming from localStorage. However, it should still work.
Theres a bug in the angular2 tpl: We must use map() instead of concatMap() in the generated method...
Btw: Ive updated the docu
Ok, it seems that it also works with concatMap(), but I changed it to flatMap() which fits better here...
@paddyfink try using
options.headers.append("Authorization", "myvalue");
instead of
options.headers.Authorization = "foobar";
then the header should be set (however it is lower cased).
Or use @Kitcheone solution...
full sample (for latest CI build):
import * as generated from "./serviceClients";
import { RequestOptionsArgs } from '@angular/http'; // ignore
export class ClientBase {
transformOptions(options: RequestOptionsArgs) {
console.log("Options: " + JSON.stringify(options));
options.headers.append("x-myheader", "myvalue");
return Promise.resolve(options);
}
}
wahouh that was quick. Thanks @rsuter . If I reinstall nswagstudio I will get the fix?
Append should already be working with the current release
yep I confirm, it's working. Big thanks, you are the man
hi @rsuter, I have changed my client according to your commit but the http call is still no beeing called. The transformOptions method gets called and successfully adds the bearer token followed by returning a promise.
I've been struggling around with this and have no clue why I never reach the line return this.http.request(url_, transformedOptions_); after the .flatMap(transformedOptions_ => { instruction. (Using the synchronous implementation works as expected but not with the new async. way)
Could it be a version mismatch of the rxjs package? I'm currently using "rxjs": "^5.0.1" with angular 2.4.7.
Thanks for your help!
@jgoelten very strange, it works for me with rxjs 5.0.0-beta.12 and ^5.0.1 with concatMap and flatMap...
Can you try to add
import 'rxjs/add/operator/mergeMap';
at the top of the generated TS file?
Thanks for your advice @rsuter ! unfortunately it is still not working. The transformOptions method returns a promise and the calling Observable.fromPromise(...) results in a PromiseObservable (zoneawarepromise):
PromiseObservable
_isScalar:false
promise:ZoneAwarePromise
scheduler:undefined
__proto__:Observable
It seems as if the converted promise does not signal the flatMap about its finished state. As a result it never reaches the next state.
The following list shows my dependent packages with their corresponding versions. Do you have a working sample reference that I might use to compare the packages?
{
"name": "angulartest",
"version": "0.0.0",
"scripts": {
"test": "karma start ClientApp/test/karma.conf.js"
},
"dependencies": {
"@angular/common": "2.4.7",
"@angular/compiler": "2.4.7",
"@angular/core": "2.4.7",
"@angular/forms": "2.4.7",
"@angular/http": "2.4.7",
"@angular/platform-browser": "2.4.7",
"@angular/platform-browser-dynamic": "2.4.7",
"@angular/platform-server": "2.4.7",
"@angular/router": "3.4.7",
"@types/node": "^7.0.5",
"angular2-platform-node": "~2.0.11",
"angular2-template-loader": "^0.6.2",
"angular2-universal": "^2.1.0-rc.1",
"angular2-universal-patch": "^0.2.1",
"angular2-universal-polyfills": "^2.1.0-rc.1",
"angular": "^1.6.2",
"aspnet-prerendering": "^2.0.3",
"aspnet-webpack": "^1.0.17",
"awesome-typescript-loader": "3.0.0-beta.13 || ^3.0.0",
"bootstrap": "^3.3.7",
"css": "^2.2.1",
"css-loader": "^0.25.0",
"es6-shim": "^0.35.1",
"event-source-polyfill": "^0.0.9",
"expose-loader": "^0.7.1",
"extract-text-webpack-plugin": "^2.0.0-rc",
"file-loader": "^0.9.0",
"html-loader": "^0.4.4",
"isomorphic-fetch": "^2.2.1",
"jquery": "^2.2.1",
"json-loader": "^0.5.4",
"preboot": "^4.5.2",
"raw-loader": "^0.5.1",
"rxjs": "^5.1.1",
"style-loader": "^0.13.1",
"sha256": "^0.2.0",
"to-string-loader": "^1.1.5",
"typescript": "^2.2.1",
"url-loader": "^0.5.7",
"webpack": "^2.2.0",
"webpack-hot-middleware": "^2.12.2",
"webpack-merge": "^0.14.1",
"zone.js": "^0.7.7"
},
"devDependencies": {
"@types/chai": "^3.4.34",
"@types/jasmine": "^2.5.37",
"chai": "^3.5.0",
"jasmine-core": "^2.5.2",
"karma": "^1.3.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^2.0.0",
"karma-cli": "^1.0.1",
"karma-jasmine": "^1.0.2",
"karma-webpack": "^1.8.0"
}
}
@jgoelten I've added a sample project here: https://github.com/NSwag/Samples/blob/master/src/SampleWebApiCoreAngular/ClientApp/app/components/app/app.component.ts (see ctor output)
Run build.bat to compile, then "dotnet run" (.NET Core development mode must be set first)
@jgoelten could you solve your problem?
@jgoelten please open a new issue if the problem persists...
@rsuter thanks to your sample I could solve the problem. It was a simple misunderstanding of the lazy observable behaviour. Thanks for your help!
@rsuter return Promise.resolve(options); solved my problem after upgrades.
Thanks a lot...
@Kitcheone's example mostly works. Except globals isn't a thing and I do not see any reasonable way to inject something into the base class.
The template doesn't even seem to offer any way to use config to add something for the class created to inject and pass to the base class.
@RicoSuter how do I do the same for HttpClient and Angular >6?
Could you please post working sample of code which changes the Headers in the options object.
I tried it like this
options = options.headers.append("Authorization", "myvalue");
But still I see only LazyUpdate property on the headers object.
@KokaChernov thats ok
Most helpful comment
full sample (for latest CI build):