I have create below rest service but getting error when call this.router.navigate(['/login']); How to create router object in service? this.router.navigate is work from Component class but it's not working from service.
import { Injectable } from '#angular/core';
import { Http, Headers, Response } from '#angular/http';
import { Router } from '#angular/router';
import { Observable } from 'rxjs/Observable';
import { apiURL } from './app.config';
#Injectable()
export class RestService {
header = new Headers();
constructor(public http: Http, private router: Router) {
}
get(url: string) {
debugger;
this.addHeader();
return this.http.get(apiURL + url, { headers: this.header }).catch(this.handleError);;
}
post(url: string, data) {
this.addHeader();
return this.http.post(apiURL + url, data, { headers: this.header }).catch(this.handleError);;
}
put(url: string, data) {
this.addHeader();
return this.http.put(apiURL + url, data, { headers: this.header }).catch(this.handleError);;
}
auth(url: string, data) {
this.addHeader();
return this.http.post(apiURL.replace('api/v1/', '') + '/' + url, data, { headers: this.header }).catch(this.handleError);
}
private extractData(res: Response) {
debugger;
let body = res.json();
return body.data || {};
}
private handleError(error: any) {
// In a real world app, we might use a remote logging infrastructure
// We'd also dig deeper into the error to get a better message
debugger;
if (error.status == '401') {
this.router.navigate(['/login']);
}
else {
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg); // log to console instead
return Observable.throw(errMsg);
}
}
private addHeader() {
this.header = new Headers();
this.header.append('Content-Type', 'application/json');
this.header.append('Authorization', 'Bearer ' + localStorage.getItem('id_token'));
}
}
Try this.router.navigate(['login']); instead. The router adds the slash itself as part of the server URI.
Related
I am using NSwag Studio to generate service class in react using typescript.
Here is an example of the generated code:
export class BookingClient {
private http: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> };
private baseUrl: string;
protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;
constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
this.http = http ? http : <any>window;
this.baseUrl = baseUrl ? baseUrl : "";
}
getMarinaData(model: MarinaDataRequest): Promise<MarinaDataResponse> {
let url_ = this.baseUrl + "/api/booking/marina/data";
url_ = url_.replace(/[?&]$/, "");
const content_ = JSON.stringify(model);
let options_ = <RequestInit>{
body: content_,
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processGetMarinaData(_response);
});
}
protected processGetMarinaData(response: Response): Promise<MarinaDataResponse> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
let result200: any = null;
result200 = _responseText === "" ? null : <MarinaDataResponse>JSON.parse(_responseText, this.jsonParseReviver);
return result200;
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<MarinaDataResponse>(<any>null);
}
}
My question is, how can I add or inject JWT for protected endpoints. Suppose that not all endpoints are protected.
Thnx for help.
Create a base class and override transformOptions method.
export class BaseClass {
protected transformOptions = async (options: RequestInit): Promise<RequestInit> => {
let token = getToken(); // your custom logic to get the token
options.headers = {
...options.headers,
Authorization: 'Bearer ' + token,
};
return Promise.resolve(options);
};
}
And in your nswag.json set:
"clientBaseClass": "BaseClass",
"extensionCode": "path/to/your/BaseClass.ts",
"useTransformOptionsMethod": true,
This will add it to all endpoints, but I suppose it doesn't hurt to send the token to the non-protected endpoints (it will be ignored).
How can i add authentication token to the file upload service? When i login in my application, i am able to retrieve the token from the backend but i am having a hard time as to how to add it the to file service. When i try to upload a file, it get an error saying "token_not_provided". As it is in my service, i have added the authentication token in my header so whenever i make a request, the server is aware of the user at hand. But with the file submission, i have no idea of how to append the authentication token to the file service
#Component({
providers:[AuthenticationService]
})
#Injectable()
export class FileUploadService {
public progress$;
public progressObserver;
public progress : number;
public token: string;
public headers:string;
constructor (private auth:AuthenticationService) {
this.progress$ = Observable.create(observer => {
this.progressObserver = observer
}).share();
}
makeFileRequest (url: string, params: string[], files: File[]) {
return Observable.create(observer => {
let formData: FormData = new FormData(),
xhr: XMLHttpRequest = new XMLHttpRequest();
for (let i = 0; i < files.length; i++) {
formData.append("uploads[]", files[i], files[i].name);
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
observer.next(JSON.parse(xhr.response));
observer.complete();
} else {
observer.error(xhr.response);
}
}
};
xhr.upload.onprogress = (event) => {
this.progress = Math.round(event.loaded / event.total * 100);
this.progressObserver.next(this.progress);
};
xhr.open('POST', url, true);
xhr.setRequestHeader(this.headers, this.auth.token);//modified
xhr.send(formData);
});
}
}
//service
updateFood(food:any) {
const body = JSON.stringify(food);
const headers = new Headers({ 'Authorization': 'Bearer ' + this.authenticationService.token });
return this.http.put('http://localhost:9000/, body, {headers: headers})
.map((data:Response) => data.json());
}
Somewhere between your xhr.open and xhr.close you can append headers
xhr.setRequestHeader(header, value);
See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader for more detailed documentation
I am learning a tutorial and an assignment on how to bind id's to http request. This is what i am currently trying to do. I want to bind the id captured in my url and when i trigger the function, it submits the id captured from the url to my service. I am have been able to capture the url but the function to send the captured id to the service is where i am having the issues. The id in the function parameter is Unused.
//Food Component
export class FoodComponent implements OnInit {
private food_id;
constructor(private httpService: HttpService, private route: ActivatedRoute) {
}
ngOnInit() {
this.route.params.subscribe(params => {
if (params['id']) {
this.food_id = params['id'];
}
})
}
//food model
foodModel = {
type: "",
location: ""
};
sendFood() {
this.httpService.send(this.food_id)
.subscribe(data => {
console.log(data);
})
}
//service
send(food: any) {
const body = JSON.stringify(food.value);
const headers = new Headers();
return this.http.post('http://localhost:8000/api/luncheons/v1/location/' + food.id + '/type', body, {
headers: headers
})
.map((data: Response) => data.json());
}
Try this,
import { foodModel } from './foodModel';
export class FoodComponent implements OnInit {
private model: foodModel; /// Make a new variable of foodModel.
ngOnInit() {
this.model = new foodModel(); // Initialize the Model
this.route.params.subscribe(params => {
if (params['id']) {
this.model.id = params['id']; ///set the parameter id to model.id
}
})
}
/// Removed the parameter food_id
sendFood() {
this.httpService.send(this.foodModel)
.subscribe(data => {
console.log(data);
})
}
//service
send(food: any) {
const body = JSON.stringify(food);
const headers = new Headers();
return this.http.post('http://localhost:8000/api/luncheons/v1/location/' + food.id + '/type', body, {
headers: headers
})
.map((data: Response) => data.json());
}
}
// Make a class file foodModel.ts and import foodModel in your component.
export class foodModel {
type: any;
location: any;
id: number = 0; /// new variable added
};
I'm fairly new to AngularJS (2.0.0-beta.16). I've managed to setup a service that pulls data from an API, via a GET request. Now, how do I set it up to run the GET request every n seconds? I've seen other posts saying you could just using this._http.get(...).interval(5000).map(...);, however when I've tried that, I get a Typescript compilation error:
Property 'interval' does not exist on type 'Observable'.
Am I making a silly mistake or is there a better pattern for doing this?
import { Injectable } from 'angular2/core';
import { Http, Response } from "angular2/http";
import { Observable } from "rxjs/Observable";
import * as _ from "js/lodash.js";
import { Foo } from "./foo";
#Injectable()
export class FooService {
fooList: Observable<Foo[]>;
constructor(private _http: Http) {
this.fooList = this._http.get('http://localhost:9090/api/').map(
response => {
var json = response.json();
if(response.ok === true) {
let newFooList: Foo[] = [];
_.forEach(json, f => {
newFooList.push(new Foo(f));
});
return newFooList;
}
throw Error("Bad status: " + response);
});
}
}
This is probably not the only (or the best) way, but it worked for me. The only issue is that the first GET request is delayed by the amount of time specified by create().
import { Injectable } from "angular2/core";
import { Http, Response } from "angular2/http";
import { Observable } from "rxjs/Observable";
import { IntervalObservable } from "rxjs/observable/IntervalObservable";
import * as _ from "js/lodash.js";
import { API_URI } from "./constants";
import { Foo } from "./foo";
#Injectable()
export class FooService {
public fooList: Observable<Foo[]>;
constructor(private _http: Http) {
this.fooList = IntervalObservable.create(2000).flatMap(
() => {
return this._http.get(API_URI);
}).map(
response => {
var json = response.json();
if(response.ok === true) {
let newFooList: Foo[] = [];
_.forEach(json, f => {
newFooList.push(new Foo(f));
});
return newFooList;
}
throw Error("Bad status: " + response);
});
}
}
I want to develop a file configuration of json and it is called with http get the constructor and return the value I want the config file to another component. But when return gives me value undefined.
My Config.json
[ {"urlServer": "http://localhost:56877"}]
My Config.Service
export class configService
{
url: string;
constructor(public _http: Http)
{
let injector = Injector.resolveAndCreate([loggerService]);
let logger = injector.get(loggerService);
try {
return this._http.get('/app/config.json',
{
headers: contentHeaders
})
.map((res: any) =>
{
let data = <configModel>res.json();
this.url = data.urlServer;
JSON.stringify(this.url);
});
}
catch (ex) {
logger.registarErros('configService', ex);
}
}
returnConfig()
{
return this.url;
}
Now my other Component
constructor(public _http: Http, public config: configService)
{
this.token = sessionStorage.getItem('token');
this.username = sessionStorage.getItem('username');
}
login(username: String, password: String)
{
let injector = Injector.resolveAndCreate([loggerService]);
let logger = injector.get(loggerService);
try
{
alert(this.config.url);
return this._http.post('http://localhost:56877/api/Login/EfectuaLogin', JSON.stringify({ username, password }),
{
headers: contentHeaders
})
.map((res: any) =>
{
let data = <authLoginModel>res.json();
this.token = data.token;
this.username = data.nome;
sessionStorage.setItem('token', this.token);
sessionStorage.setItem('username', this.username);
return Observable.of('authObservable');
});
}
catch (ex) {
logger.registarErros('authentication', ex);
}
}
I no longer know how to solve the problem, I need your help, I'm not very experienced with Angular 2.
Thanks very much.
The problem here is that the config is load asynchronously. You could use something like that leveraging the flatMap operator:
#Injectable()
export class ConfigService {
urlServer:string;
constructor(public _http: Http) {
}
getConfig() {
if (this.urlServer) {
return Observable.of(this.urlServer);
}
return this._http.get('/app/config.json', {
headers: contentHeaders
})
.map((res: any) => {
let data = <configModel>res.json();
return data.urlServer;
}).do(urlServer => {
this.urlServer = urlServer;
});
}
}
and in your component:
login(username: String, password: String) {
return this.configService.getConfig().flatMap(urlServer => {
this._http.post('http://localhost:56877/api/Login/EfectuaLogin',
JSON.stringify({ username, password }),
{
headers: contentHeaders
})
.map((res: any) =>
{
let data = <authLoginModel>res.json();
this.token = data.token;
this.username = data.nome;
sessionStorage.setItem('token', this.token);
sessionStorage.setItem('username', this.username);
return data; // or something else
});
}
});
}
Another approach would be boostrap asynchronously after having loaded the configuration:
var app = platform(BROWSER_PROVIDERS)
.application([BROWSER_APP_PROVIDERS, appProviders]);
service.getConfig().flatMap((url) => {
var configProvider = new Provider('urlServer', { useValue: urlServer});
return app.bootstrap(appComponentType, [ configProvider ]);
}).toPromise();
See this question for the second approach:
angular2 bootstrap with data from ajax call(s)
You can go further by mixing the last approach with a CustomRequestOptions:
import {BaseRequestOptions, RequestOptions, RequestOptionsArgs} from 'angular2/http';
export class CustomRequestOptions extends BaseRequestOptions {
merge(options?:RequestOptionsArgs):RequestOptions {
options.url = 'http://10.7.18.21:8080/api' + options.url;
return super.merge(options);
}
}
See this question:
Angular 2 - global variable for all components