Getting the http post canceled when subscribing from a service - node.js

Stuck in this error for a week. Cannot send a simple post request to the heroku server using the Angular HttClient. Defined all the services in the provider section in the main app Module. The Error Handling service is not logging any error after sending the post request(This service works fine that i have tested in another project).
The component is defined in a different module but services are defined and provided in the root app.module.ts
These Modules that components live are imported in the main app module.
But no matter what the post request being canceled!!.
API Params
email: string
password: string
AuthModel
Model using for defining the data params for API
export interface AuthModel {
email: string;
password: string
}
AuthService.ts
This is the service i used to inject into my component.ts file for subscribing. This service also uses another service to handle the error cases HandleError
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
};
#Injectable({
providedIn: 'root'
})
export class AuthService {
signUpUrl = 'myurl';
private handleError: HandleError;
constructor(private http: HttpClient, private httpErrorService: HttpErrorService) {
this.handleError = this.httpErrorService.createHandleError('AuthService'); //Problem lies here
}
signUp(authModel: AuthModel) : Observable<AuthModel>
{
return this.http.post<AuthModel>(this.signUpUrl,authModel,httpOptions).pipe( catchError(this.handleError('signup',authModel)) );
}
}
component.ts
Submit function is called when button is clicked after entering the data
Submit(): void {
this.authModel!.email = this.emailHolder.value;
this.authModel!.password = this.passwordHolder.value;
this.authService.signUp(this.authModel).subscribe((res)=> {console.log(res)});
}

The problem was with my handleError function, it get's canceled not matter the response was. So make sure guys to write a proper errorHandling function, else you will get unintended result.

Related

Calling an onCall function in Firebase Functions using AngularFire results in a 404 error, while returning the expected result

I have created a few onCall cloud functions using Firebase. These functions interact with Stripe through the API. When I use AngularFire, or more specifically, AngularFireFunctions to call these said cloud functions, I receive the error message A bad HTTP response code (404) was received when fetching the script. in Chrome developer console. Yet, the expected result is received with no problem and the Firebase console displays a 200 response with no error messages or warnings. The project is entirely hosted on Firebase.
The 404 error also does not display a file that it is connected to in the console as such errors typically do within that console.
UPDATE
I also feel it is relevant to include, the Stripe developer logs in the dashboard reflect no errors, but a successfull call upon checking.
I have also tried to remove the call to Stripe in the cloud function and simply only return a string return 'The customer ID is:'+ ${data.customerId}+'. Thank you.' and still received the same error message.
I have also tried this solution, https://github.com/angular/angularfire/issues/1933#issuecomment-432910986 with the following code being placed inside app.module.ts however, am unable to find where FunctionsRegionToken would be defined to be able to import it.
providers: [
{ provide: FunctionsRegionToken, useValue: 'us-central1' }
]
Although, I'm not sure how changing the region to the same region the function is being called from currently would make any difference.
When you explore the Network tab of the developer console and visit the page that calls the function, you see that something is trying to call http://localhost:4200/firebase-messaging-sw.js which doesn't exist. The amount of calls to this file and the errors in the console coincide with each other which leads me to believe they are related.
END OF UPDATE
I have tried to add CORS to my cloud function (and am using it in onRequest functions), I've tried rewriting my cloud function, and even tried changing the client side function that calls the onCall to no avail. The only way to remove the error is to remove the call to the function, thus I've narrowed it down to something with the AngularFireFunctions.
What I am using and the versions
Angular V13
Firebase 9.6.7
Angular Fire 7.2.1
Node 16.13.1
What follows is my code, broken up into sections.
Cloud function
const cors = require('cors')({origin: true});
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
const FieldValue = require('firebase-admin').firestore.FieldValue;
admin.initializeApp();
const firebaseApp = admin.app();
const firebaseDB = firebaseApp.firestore();
const Stripe = require('stripe');
const stripe = Stripe(functions.config().stripe.key);
export const retrieveCustomer = functions.https.onCall( async(data) => {
if(data.customerId) {
const customer = await stripe.customers.retrieve(data.customerId);
if(customer) {
return customer;
} else {
throw new functions.https.HttpsError('unknown', 'An unknown error occurred, please try again.');
}
} else {
throw new functions.https.HttpsError('invalid-argument', 'A customer ID must be provided.');
}
});
Angular Service
import { Injectable } from '#angular/core';
import { AngularFirestore } from '#angular/fire/compat/firestore';
import { AngularFireFunctions } from '#angular/fire/compat/functions';
#Injectable({
providedIn: 'root'
})
export class BillingService {
constructor( private aff: AngularFireFunctions, private afs: AngularFirestore ) { }
RetrieveCustomer(customerId:string) {
const callable = this.aff.httpsCallable('retrieveCustomer');
return callable({
customerId: customerId
});
}
}
Angular Component
import { Component, OnInit, AfterContentInit } from '#angular/core';
import { BillingService } from 'src/app/shared/services/billing/billing.service';
#Component({
selector: 'app-billing-settings',
templateUrl: './billing-settings.component.html',
styleUrls: ['./billing-settings.component.css']
})
export class BillingSettingsComponent implements OnInit, AfterContentInit {
public stripeCustomer!: any;
constructor( private billingService: BillingService ) { }
ngOnInit(): void {
}
ngAfterContentInit(): void {
this.billingService.RetrieveCustomer('cus_LGRX8TPVF3Xh0w').subscribe((customer:any) => {
console.log(customer);
});
}
}

How to do make >2 independent / parallel http requests in Angular 2

Basic Situation:
I am building a form in my app built with Angular CLI. The form has three select boxes containing long lists of options. These options are populated via http requests to a server. I invoke three methods in ngOnInit to make these http requests (see code below). No matter what sequence I call them in, only the first two requests ever complete.
Eventually the console will show the following error for the third request:
HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: "http://my-corporate-url:3001/db/depts?deptName=", ok: false, …}
headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, headers: Map(0)}
status: 0
statusText: "Unknown Error"
url: "http://my-corporate-url:3001/db/depts?deptName="
ok: false
name: "HttpErrorResponse"
message: "Http failure response for http://my-corporate-url:3001/db/depts?deptName=: 0 Unknown Error"
error: ProgressEvent {isTrusted: true, lengthComputable: false, loaded: 0, total: 0, type: "error", …}
__proto__: HttpResponseBase
I could "chain" the three http requests to be called sequentially, but I want the http services to be reusable in other forms I build which will have the same select box input elements.
Yes I already Read:
There are a few Stackoverflow questions out there similar to this one (especially this question), but none of them address this specific issue of being able to make only 2 http requests. There is mention of using mergeMap and forkJoin, but these appear to designed for calling an array of identical requests.
My Code:
The component which is making the requets:
import { Component, OnInit } from '#angular/core';
import { NodeHTTPService } from '../node-http.service';
#Component({
...
})
export class NewServiceDeskGroupComponent implements OnInit {
existingGroups;
deptArray;
locArray;
group: string = "";
dept: string = "";
loc: string = "";
constructor(private _nodeHTTPService: NodeHTTPService) { }
ngOnInit() {
this.queryGroupNames();
this.queryBBB();
this.queryDepts();
}
queryGroupNames() {
console.log('begin querying for groups')
this._nodeHTTPService.getSDMGroups().subscribe(
data => {this.existingGroups = data},
err => console.log(err),
() => console.log('done loading groups')
);
}
queryBBB() {
console.log('begin querying for branches')
this._nodeHTTPService.queryBranches(this.loc).subscribe(
data => {this.locArray = data},
err => console.log(err),
() => console.log('done loading branches')
);
}
queryDepts() {
console.log('begin querying for departments')
this._nodeHTTPService.getDepts(this.dept).subscribe(
data => {this.deptArray = data},
err => console.log(err),
() => console.log('done loading departments')
);
}
}
My node-http.service.ts file:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type' : 'application/json' })
};
#Injectable({
providedIn: 'root'
})
export class NodeHTTPService {
constructor(private http: HttpClient) { }
getSDMGroups() {
let groups = this.http.get('http://my-corporate-url:3001/db/sdm-groups')
return groups;
}
queryBranches(i) {
let bbbs = this.http.get(`http://my-corporate-url:3001/db/bbb-full-service?bbb=${i}`);
return bbbs;
}
getDepts(i) {
if (!i) { i = ''};
let depts = this.http.get(`http://my-corporate-url:3001/db/depts?deptName=${i}`);
return depts;
}
}
What I tried:
I tried commenting out each of the three methods invoked in ngOnInit to see if one of them is erring out. I've also tried shuffling the order of the three method invocations. In every scenario, the browser can successfully execute any 2 of the 3 methods, but the 3rd never completes.
Any pointers? Thank you!
The error you're receiving looks like a bad request. Specifically, I think you're trying to call the departments endpoint without a required dept query param. (This is hard to determine without seeing your server side code)
Your error:
Http failure response for
http://my-corporate-url:3001/db/depts?deptName=: 0 Unknown Error
If you set a correct value for this.dept before invoking your departments endpoint, do you get it to work?
I would also recommend setting a breakpoint in the server code to see what the department's endpoint is receiving from the client. It could be that your server is throwing an exception because you're immediately trying to do something with the query param deptName but it's empty so your api barfs.
Keep in mind, in JavaScript, an empty string ('') is a falsy value.
Since you're calling all your endpoints at once like this:
this.queryGroupNames();
this.queryBBB();
this.queryDepts();
You will need to chain those together if the previous call needs to pass data to the following call. If that isn't the case, and you just want to execute all requests at once, I would recommend using Promise.all
Promise.all([
this._nodeHTTPService.getSDMGroups(),
this._nodeHTTPService.queryBranches(this.loc),
this._nodeHTTPService.getDepts(this.dept)
]);

Unable to store the access token in angular constructor

I am able to get the access token but unable to use in a constructor method in angular service. console.log just prints the token but it is not getting assigned to a variable that I need to do.
Portion of my code.
constructor(private http: HttpClient) {
// get the access_token via Node JS
this.http.get(this.apiUrl + '/api/getToken').subscribe(d=>{
this.token = JSON.stringify(d);
console.log(this.token);
})
}
If you need to use the token in the constructor, make sure it is already received.
constructor(private http: HttpClient) {
this.http.get(this.apiUrl + '/api/getToken').subscribe(d=>{
this.token = JSON.stringify(d);
console.log(this.token);
// do your stuff
// or invoke your method
})
}
Or if you want to perform some specific stuff with the token in another method myMethod, try this
myMethod(private http: HttpClient) {
this.http.get(this.apiUrl + '/api/getToken').subscribe(d=>{
this.token = JSON.stringify(d);
console.log(this.token);
// some operation, involved with token
})
}
In this case, it is ensured that the token is retrieved and available before using it.

Nest.js And Restful CRUD, Why Isn't This Posting?

I have an Angular service that has successfully posted to Firebase and to Postgres through a PHP middleware called DreamFactory. The Angular app works. The problem is in the Nestjs controller #Post() or service add() below. I want to post a json object called recordData. I'm getting an empty object instead of my json data, which is correct in the Angular service. Server console.log results:
recordData in controller: {}
req: {}
recordData in service: {}
The Angular CORS proxy server is working in the Angular dev terminal:
[HPM] POST /api/members -> http://localhost:3000
Angular is using the dev server port 4200, Nestjs is on 3000. The typical development setup.
What's wrong? The payload isn't arriving in the controller. I'm new to server coding.
Angular http.service.ts:
private api = '/api/';
...
public addRecord(dbTable: string, recordData): Observable<any> {
return this.http
.post(`${this.api}${dbTable}`, recordData);
// For this example I'm posting to localhost:3000/api/members db table.
}
My members Nest controller. #Get works, #Post doesn't.
#Controller('api/members') // /members route
export class MembersController {
constructor(private readonly membersService: MembersService) {}
#Get()
async findAll(): Promise<Members[]> {
return await this.membersService.findAll();
}
#Post()
async addItem(#Req() req, #Body() recordData: AddMemberDto) {
console.log('recordData in controller: ', recordData);
console.log('req: ', req.body);
const result: Members = await this.membersService.addItem(recordData);
if (!result)
throw new HttpException('Error adding new Member', HttpStatus.BAD_REQUEST);
return result;
}
There were several problems, some of which I eventually fixed in the edits above. However, the main problem was I needed header info as such. While I had these for other backends they didn't seem to be required for Nestjs. Wrong idea. This is my Angular http.service setup.
private headers = new HttpHeaders()
.set('content-type', 'application/json')
.set('observe', 'response');
public addRecord(dbTable: string, recordData): Observable<any> {
return this.http
.post(`${this.api}${dbTable}`, recordData, {headers: this.headers});
}
I also want to note that many implementations of Nestjs use a dto type for the data param, so recordData: AddMemberDto in the Nestjs controller. I removed it and it works fine.

Calling REST api from angular2

I've finished the angular2 heroies tutorial https://angular.io/docs/ts/latest/tutorial/ and now I'am trying to call a ral REST api that i've made with Node, Postgresql and Express.
The angular2 code calling the API looks like this:
...
export class HeroService{
private heroesUrl = 'http://192.168.4.13:3000/api/boxes'; //URL til api
private headers = new Headers({'Content-Type': 'application/json'});
constructor(private http: Http) {}
getHeroes(): Promise<Hero[]> {
return this.http.get(this.heroesUrl)
.toPromise()
.then(response => response.json().data as Hero[])
.catch(this.handleError);
}
...
The browser console shows:
An error occurred Response {_body: Object, status: 404, ok: false, statusText: "Not Found", headers: Headers…}
EXCEPTION: Uncaught (in promise): Response with status: 404 Not Found for URL: null
Picture from REST API
And I can see that my API isen't being called.
Any ideas to what I'am missing out?
Best regards.
I figurd out that I needed to remove these lines for the backend to be called:
// Imports for faking the http service - in-memory web api
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService } from './in-memory-data.service';
I thought that Angular2 would ignore them when not being used, but the caused the new backend API not to being called.

Resources