angular2 – handle same response error multiple times - http

I am building an angular2 app. I have a global service called HttpClient which is handling all requests before angulars builtin http service gets fired. Also this service handles all my response errors by checking the status codes:
import { Injectable } from '#angular/core';
import { Headers, Http, Response, } from '#angular/http';
import { MessageProvider } from '../../providers/message/message.provider'
#Injectable()
export class HttpClient {
private webApi = 'http://localhost:8080/api/v1/';
constructor(
private http: Http,
private messageProvider: MessageProvider) { }
get(url: string): Promise<Response> {
return this.http.get(this.webApi + url, {headers: this.createAuthorizationHeader()})
.toPromise()
.catch(this.handleError.bind(this));
}
post(url: string, data: Object): Promise<Response> {
return this.http.post(this.webApi + url, data, {headers: this.createAuthorizationHeader()})
.toPromise()
.catch(this.handleError.bind(this));
}
put(url: string, data: Object): Promise<Response> {
return this.http.put(this.webApi + url, data, {headers: this.createAuthorizationHeader()})
.toPromise()
.catch(this.handleError.bind(this));
}
delete(url: string): Promise<Response> {
return this.http.delete(this.webApi + url, {headers: this.createAuthorizationHeader()})
.toPromise()
.catch(this.handleError.bind(this));
}
private handleError (error: any) {
var status: number = error.status;
if(status == 401) {
this.messageProvider.setMessage(error);
this.messageProvider.message.text = "You have to be logged in to reach this page.";
}
let errMsg = (error.message)
? error.message
: status
? `${status} - ${error.statusText}`
: 'Server error';
console.error(errMsg); // log to console instead
return error;
}
private createAuthorizationHeader() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
if (localStorage.getItem('token'))
headers.append('Authorization', 'Bearer ' + localStorage.getItem('token'));
return headers;
}
}
Now, lets pretend the calling component was about login:
import { Component, Input, OnInit, OnDestroy } from '#angular/core';
import { Router } from '#angular/router';
import { Login } from '../../core/classes/login/login'
import { AuthenticationProvider } from '../../providers/authentication/authentication.provider'
import { MessageProvider } from '../../providers/message/message.provider'
#Component({
selector: 'my-login',
templateUrl: 'app/components/login/login.component.html'
})
export class LoginComponent implements OnInit, OnDestroy {
#Input() login: Login;
error: any;
constructor(
private authProvider: AuthenticationProvider,
private route: Router,
private messageProvider: MessageProvider) { }
ngOnInit() {
this.login = new Login();
}
ngOnDestroy() {
this.messageProvider.setDefault();
}
onSubmit() {
this.authProvider.login(this.login)
.then(auth => {
if (this.authProvider.isAdmin())
this.route.navigateByUrl('admin/users');
else if (this.authProvider.isLoggedIn())
this.route.navigateByUrl('/');
})
.catch(error => {console.log(error);});
}
}
In this case I don't want the error from the HttpClient ("You have to be logged in to reach this page.") but a more customized message like "No user found". I know that I could do something like the following but there is no error anymore:
onSubmit() {
this.authProvider
.login(this.login)
.then(auth => {
if (this.authProvider.isAdmin())
this.route.navigateByUrl('admin/users');
else if (this.authProvider.isLoggedIn())
this.route.navigateByUrl('/');
})
.catch(error => {
var status: number = error.status;
if(status == 401) {
this.messageProvider.setMessage(error);
this.messageProvider.message.text = "No user found.";
}
});
}
So is there a way to maybe cause another error in the catch() function within the HttpClient? So I can handle the error again in my LoginComponent.

I think you can throw in the catch method to essentially "map" your error. If you want to also update your messageProvider then you could do...
.catch(error => {
var status: number = error.status;
var newError = {};
if(status == 401) {
this.messageProvider.setMessage(error);
this.messageProvider.message.text = "No user found.";
newError.errorMessage = "No user found.";
}
throw newError;
});
Confirmed with this example:
var obs = Observable.of(12);
obs.map((value) => {
throw "blah";
}).catch((error) => {
if(error === "blah") {
throw "baz";
} else {
return Observable.of("Hello");
}
}).subscribe((value) => {
console.log("GOOD: " + value);
}, (error) => {
console.log("ERR: " + error);
});
//Logs ERR: baz

Related

How to Make http Request to My Project API from Firebase Cloud function?

Hello I am trying to make an API Post request using Firebase cloud function,Here are the code.
My effort is to get details from cloud and make an http request to my project's API. But i am getting an error of can not find module!!i have already put it.
so how to make an api call??
Here is my index.ts
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import {TenantServiceProxy, CreateTenantInput} from '../../src/app/cloud/cloud-service';
let _tenantService: TenantServiceProxy;
const tenant = new CreateTenantInput();
admin.initializeApp();
export const onOrganizationUpdate =
functions.firestore.document('organizations/{id}').onUpdate(change => {
const after = change.after.data()
const payload = {
data: {
OrganizationId: String(after.OrganizationId),
Name: String(after.Name),
IsDeleted: String(after.IsDeleted)
}
}
console.log("updated", payload);
https.get('https://reqres.in/api/users?page=2', (resp: any) => {
let data = '';
// A chunk of data has been recieved.
resp.on('data', (chunk: any) => {
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
console.log("-------------------->",JSON.parse(data));
});
}).on("error", (err: any) => {
console.log("Error: " + err.message);
});
return admin.messaging().sendToTopic("OrganizationId", payload)
})
export const onOrganizationCreate =
functions.firestore.document('organizations/{id}').onCreate(change=>{
const onCreationTime =change.data()
const payload={
data:{
organizationId:String(onCreationTime.organizationId),
name:String(onCreationTime.name),
isDeleted:String(onCreationTime.isDeleted)
},
}
console.log("created",payload);
tenant.pkOrganization = payload.data.organizationId;
tenant.name = payload.data.name;
tenant.isDeleted = Boolean(payload.data.isDeleted);
_tenantService.createTenant(tenant).subscribe(()=>{
console.log("created",payload);
});
return admin.messaging().sendToTopic("OrganizationId",payload)
})
Here is the cloud.service.module.TS
//cloud service module
import { AbpHttpInterceptor } from '#abp/abpHttpInterceptor';
import { HTTP_INTERCEPTORS } from '#angular/common/http';
import { NgModule } from '#angular/core';
import * as ApiServiceProxies from '../../app/cloud/cloud-service';
#NgModule({
providers: [
ApiServiceProxies.TenantServiceProxy,
{ provide: HTTP_INTERCEPTORS, useClass: AbpHttpInterceptor, multi: true }
]
})
export class CloudServiceModule { }
Here is My api call service
#Injectable()
export class TenantServiceProxy {
private http: HttpClient;
private baseUrl: string;
protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;
constructor(#Inject(HttpClient) http: HttpClient, #Optional() #Inject(API_BASE_URL) baseUrl?: string) {
this.http = http;
this.baseUrl = baseUrl ? baseUrl : '';
}
createTenant(input: CreateTenantInput | null | undefined): Observable<void> {
let url_ = this.baseUrl + '/api/services/app/Tenant/CreateTenant';
url_ = url_.replace(/[?&]$/, '');
const content_ = JSON.stringify(input);
const options_: any = {
body: content_,
observe: 'response',
responseType: 'blob',
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
};
return this.http.request('post', url_, options_).pipe(_observableMergeMap((response_: any) => {
return this.processCreateTenant(response_);
})).pipe(_observableCatch((response_: any) => {
if (response_ instanceof HttpResponseBase) {
try {
return this.processCreateTenant(<any>response_);
} catch (e) {
return <Observable<void>><any>_observableThrow(e);
}
} else {
return <Observable<void>><any>_observableThrow(response_);
}
}));
}
protected processCreateTenant(response: HttpResponseBase): Observable<void> {
const status = response.status;
const responseBlob =
response instanceof HttpResponse ? response.body :
(<any>response).error instanceof Blob ? (<any>response).error : undefined;
const _headers: any = {}; if (response.headers) { for (const key of response.headers.keys()) { _headers[key] = response.headers.get(key); } }
if (status === 200) {
return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => {
return _observableOf<void>(<any>null);
}));
} else if (status !== 200 && status !== 204) {
return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => {
return throwException('An unexpected server error occurred.', status, _responseText, _headers);
}));
}
return _observableOf<void>(<any>null);
}
}
I have defined the module in my services.

REST API auth error : WooCommerce

Been trying to fetch products from WooCommerce REST API now forever and my brain is bleeding :'( I followed all instructions on woocommerce and github/woocommerce and I can't for my life get anything in Postman with Basic Auth:
But when I select Auth 1.0 - I get all products:
But then if I take the Auth 1.0 generated URL and put it in my browser:
..Instructions under Authentication over HTTP (here) describes the parameters which are generated in URL automatically when i select Auth 1.0 in Postman - but how am I gonna generate those in my React component?
const APP_URL = 'http://0.0.0.0:80'
const CONSUMER_KEY = 'ck_xxxx'
const CONSUMER_SECRET = 'cs_xxxx'
const PRODUCT_URL = `${APP_URL}/wp-json/wc/v2/products?consumer_key=${CONSUMER_KEY}&consumer_secret=${CONSUMER_SECRET}`
fetch(PRODUCT_URL).then(res => {
if(res.status === 200){
return json
} else {
console.log("ERROR RESPONSE STATUS: " + status);
}
}).then( json => {
console.log(json)
})
})
So thankful for all input!
I think this problem may be solved by below code using "Interceptor" concept...
import {
Injectable,
// Injector
} from '#angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse
} from '#angular/common/http';
// import { Router } from '#angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
// import { AuthService } from './auth.service';
import { config } from '../config/config';
#Injectable()
export class AppInterceptor implements HttpInterceptor {
constructor(
// private injector: Injector,
// private router: Router
) { }
private includeWooAuth(url) {
const wooAuth = `consumer_key=${config.consumerKey}&consumer_secret=${config.secretKey}`;
const hasQuery = url.includes('?');
let return_url = '';
if (hasQuery) {
return_url = wooAuth;
} else {
return_url = '?' + wooAuth;
}
return return_url;
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// const auth = this.injector.get(AuthService);
const authRequest = request.clone({
setHeaders: {
// Authorization: `Bearer ${auth.getToken()}`
},
url: `${config.basePath}/${request.url}${this.includeWooAuth(request.url)}`
});
return next.handle(authRequest)
.catch(err => {
if (err instanceof HttpErrorResponse && err.status === 0) {
console.log('Check Your Internet Connection And Try again Later');
} else if (err instanceof HttpErrorResponse && err.status === 401) {
// auth.setToken(null);
// this.router.navigate(['/', 'login']);
}
return Observable.throw(err);
});
}
}
This code will be kept into http.interceptor.ts. Obviously, you should initialize the consumer key and other details of woocommerce API into a constant variable. After that you create a service for show the list of the product like this:
retriveProducts(query: ProductQuery = {}): Observable<RetriveProductsResponse> {
return this.httpClient.get(`products`, {params: this.wooHelper.includeQuery(query), observe: 'response'})
.pipe(
map(value => this.wooHelper.includeResponseHeader(value)),
catchError(err => this.wooHelper.handleError(err)));
}
And call this service to the product.ts file like this:
getProducts() {
this.woocommerceProductsService.retriveProducts()
.subscribe(productResponse => {
this.products = productResponse.products;
}, error => this.errorMessage = <any>error);
}
I have used these above code into my project. I think it will help you.

(Firebase|Ionic) GoogleAuth delayed response wrong return before finished?

on my login Page i've got a button that is calling this function
googleauth(){
if(this.auth.signInGoogle()){
alert("1");
if(this.auth.getcurrentUser().displayName){
alert("2");
this.gameStatus.players[0].name = this.auth.getcurrentUser().displayName;
alert("3");
this.navCtrl.setRoot(HomePage);
}
}else{
alert("googleauth else");
}
}
in my auth provider this is the signInGoogle() function
signInGoogle(){
this.googleplus.login({
'webClientId' : '',
'offline' : true
})
.then((res)=>{
const firecreds = firebase.auth.GoogleAuthProvider.credential(res.idToken);
firebase.auth().signInWithCredential(firecreds).then((success)=>{
alert("auth1");
return true;
}).catch((err)=>{
alert('Firebase auth failed ' + err);
})
}).catch((err)=>{
alert('Error:' + err);
return false;
});
}
This is whats displayed via alert on my phone when i click on the button:
googleauth else
auth1
auth1 is above return true, so the stuff inside if(this.auth.signInGoogle()){..} should be called, but instead the else {..} part is called.
the googleauth else alert is called before the auth1 alert is there something like a waiting function i have to use? is the functions running in threads? how can this happen? how could i fix it?
Thank you guys in advance
Edit
my account is shown in firebase authentication page
The whole authProvider
import { Injectable } from '#angular/core';
import 'rxjs/add/operator/map';
import { GooglePlus } from '#ionic-native/google-plus';
import * as firebase from 'firebase/app';
import { GamestatusProvider } from '../../providers/gamestatus/gamestatus';
#Injectable()
export class AuthProvider {
constructor(public googleplus: GooglePlus) {}
signInGoogle(){
this.googleplus.login({
'webClientId' : '..',
'offline' : true
})
.then((res)=>{
const firecreds = firebase.auth.GoogleAuthProvider.credential(res.idToken);
firebase.auth().signInWithCredential(firecreds).then((success)=>{
alert("auth1");
return true;
}).catch((err)=>{
alert('Firebase auth failed ' + err);
})
}).catch((err)=>{
alert('Error:' + err);
return false;
});
}
getcurrentUser(){
return firebase.auth().currentUser;
}
}
export class LoginPage {
constructor(public navCtrl: NavController, public navParams: NavParams, public auth: AuthProvider, public gameStatus: GamestatusProvider) {
firebase.auth().onAuthStateChanged(firebaseUser => {
if(firebaseUser){
this.navCtrl.setRoot(HomePage);
}
});
}
ionViewDidLoad() {
console.log('ionViewDidLoad LoginPage');
}
anonAuth(){
this.auth.signInAnonym();
}
googleAuth(){
this.auth.signInGoogle();
}
}
export class AuthProvider {
constructor(public googleplus: GooglePlus, public gameStatus: GamestatusProvider) {}
signInAnonym(){
firebase.auth().signInAnonymously();
}
signInGoogle(){
this.googleplus.login({
'webClientId' : webClientIdGooglePlusApi,
'offline' : true
})
.then((res)=>{
const firecreds = firebase.auth.GoogleAuthProvider.credential(res.idToken);
firebase.auth().signInWithCredential(firecreds).then((success)=>{
return true;
}).catch((err)=>{
alert('Firebase auth failed ' + err);
})
}).catch((err)=>{
alert('Error:' + err);
return false;
});
}
signOut(){
firebase.auth().signOut();
}
}
is Working, but i still would love to know why my first attempt didnt worked?

in typescript How to write http service in function

Here i know hou to use http service in this way but how can i write service when its in function Like
export class studentController {
GetStudentData() {
constructor(http: Http) {
http.get('api/Employee').subscribe(result => {
this.student = result.json();
})
}
}
export class StudentMastre {
stdID: Number;
stdName: string;
email: string;
Phone: string;
Address: string;
}
You need to make a service to request the data and get, then use the service inside the component to get the data,
Your sample service should be,
#Injectable()
export class CategoryService {
constructor(private http: Http) { }
c(): Observable<StudentMastre[]> {
let wikiUrl = return this.http
.get('api/Employee')
.map(this.extractData)
.catch(this.handleErrors);
}
private extractData(res: Response) {
let data = res.json();
return data;
}
private handleErrors (error: Response | any) {
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
then in your component,
this.sampleService.
this.categoryService.getCategoriesService().subscribe(students=> {
this.students= students;
}, error => this.errorMessage = error);

Uncaught TypeError: result.subscribe is not a function

I'm getting the following error: Uncaught TypeError: result.subscribe is not a function
Here is also a screenshot of the error:
But I did tried to catch the error. Below you can see my code.
login.component.ts:
import { Component } from '#angular/core';
import { UserService } from '../../services/user.service';
import { User } from '../../models/user';
import {ToasterContainerComponent, ToasterService, ToasterConfig} from 'angular2-toaster/angular2-toaster';
#Component({
moduleId: module.id,
selector: 'login',
directives: [ToasterContainerComponent],
templateUrl: 'login.component.html',
providers: [UserService, ToasterService]
})
export class LoginComponent {
user: User = new User();
loginRes: String;
private toasterService: ToasterService;
public toasterconfig: ToasterConfig = new ToasterConfig({
showCloseButton: true,
tapToDismiss: false,
timeout: 0
});
constructor(private _userService: UserService, toasterService: ToasterService) {
this.toasterService = toasterService;
}
data = {};
onSubmit() {
this._userService.login(this.user)
.subscribe(
res => {
console.log("res onSubmit");
console.log(res);
},
function(error) { console.log("Error happened" + error)}
);
}
}
user.service.ts:
import { Injectable } from '#angular/core';
import { Headers, RequestOptions, Http, Response } from '#angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { User } from '../models/user';
#Injectable()
export class UserService {
private loginUrl: string;
constructor(private _http: Http) {
}
login(user: User) {
this.loginUrl = "http://localhost:3000/api/auth/login";
let data = { "username": user.username, "password": user.password };
let body = JSON.stringify(data);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this._http.post(this.loginUrl, body, options)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body || {};
}
private handleError(error: any) {
console.log('Yup an error occurred', error);
return error.message || error;
}
}
As you can see I have tried to catch the error in the login() method in user.service.ts. Anyone that maybe knows how I can
solve this?
Your handleError() function needs to return an Observable
If you look at the HTTP Client Angular 2 docs there is an example, but for your specific case
Replace
private handleError(error: any) {
console.log('Yup an error occurred', error);
return error.message || error;
}
with
private handleError(error: any) {
console.log('Yup an error occurred', error);
return Observable.throw(error.message || error);
}

Resources