API in mean stack - node.js

Is it possible to do the following with service in angular6?
How to call api for the following requirement?
1. Mandatory properties check
2. return response code 400 with right message if there is any mandatory check failures
3. data type validations
4. return response code 400 with right message
5. Initialize DB call
6.run DB queries and return response
7. If any errors during the DB call, return reponse code 500 with right message
8.if success then return the response object.
This is something new to me , hence don't know how to implement it. So couldn't try anything .
//blog.service.ts
import { Injectable, Inject, Output, EventEmitter } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable } from 'rxjs';
import { APP_CONFIG, AppConfig } from '../app.config';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class BlogService {
#Output() userLoggedIn: EventEmitter<any> = new EventEmitter();
constructor(private http: HttpClient, #Inject(APP_CONFIG) private _config: AppConfig) { }
////////////////////////////////////////////////////
Save(blogForm: any): Observable<any> {
return Observable.create(observer => {
this.http.post(this._config.apiEndpoint + '/newblog',
JSON.stringify(blogForm), { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }
)
.subscribe((response: Response) => {
observer.next(response);
observer.complete();
});
});
}
////////////////////////////////////////////////////
allBlogs(): any{
return this.http.get(this._config.apiEndpoint + '/getblogs').pipe(map(response=>response));
}
////////////////////////////////////////////////////
recentBlogs(): any{
return this.http.get(this._config.apiEndpoint + '/get-recent-blogs').pipe(map(response=>response));
}
////////////////////////////////////////////////////
viewBlog(blog_id:number): any{
return this.http.get(this._config.apiEndpoint+'/viewblog/'+blog_id).pipe(map(response=>response));
}
////////////////////////////////////////////////////
datewiseBlogs(year:any,month:any): any{
return this.http.get(this._config.apiEndpoint+'/year-blogs/'+year+'/month/'+month).pipe(map(response=>response));
}
////////////////////////////////////////////////////
deleteblog(blogid): Observable<any> {
return Observable.create(observer => {
this.http.post(this._config.apiEndpoint+'/deleteblog', { _id: blogid }, { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }
).subscribe((response: Response) => {
observer.next(response);
observer.complete();
});
});
}
////////////////////////////////////////////////////
editblog(blogForm: any): Observable<any> {
return Observable.create(observer => {
this.http.post(this._config.apiEndpoint + '/updateblog',
JSON.stringify(blogForm), { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }
).subscribe((response: Response) => {
observer.next(response);
observer.complete();
});
});
}
////////////////////////////////////////////////////
}
Expected result is to call the api in the service above and do other operations as listed above.

Related

MEAN stack delete request has 404 not found error

My post request and list all request are working fine, but I have problem getting my delete request to work. I have tested in Postman, but still have error. I think my delete url is fine, I can console log and see the item id been selected and show at the end of the url when making the request, I don't know what 's wrong.
delete.component.ts
deleteItem(): void {
console.log(this.currentItem._id);
alert("You had redeemed free food "+this.currentItem.itemToDonate);
this.charityService.deleteItem(this.currentItem._id).subscribe(
() => console.log("All of this food item has been redeemed"),
(err) => console.log(err)
)
}
charity.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { identifierModuleUrl } from '#angular/compiler';
//import { DonateComponent } from '../donate/donate.component';
const AUTH_API = 'http://localhost:3000/api/auth/donate';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json'})
};
#Injectable({
providedIn: 'root'
})
//post new donates to the database, list all items on the beneficiary page
//update quantity after redeem, delete item if the quantity is 0
export class CharityService {
constructor(private http: HttpClient) { }
donate(itemToDonate: string, quantity: number): Observable<any> {
return this.http.post(AUTH_API, {
itemToDonate, quantity
}, httpOptions);
}
listItem(): Observable<any> {
return this.http.get(AUTH_API, {});
}
receive(id: string): Observable<any> {
return this.http.put(`${AUTH_API}/update/${id}`, httpOptions)
.pipe(
catchError((err, caught) => {
console.error(err);
throw err;
})
);
}
getItem(id: string): Observable<any> {
return this.http.get(`${AUTH_API}/${id}`);
}
deleteItem(id: string): Observable<any> {
return this.http.delete(`${AUTH_API}/${id}`)
}
}
route.js
const controller_donate = require("../controllers/donate.controller");
const controller_receive = require("../controllers/receive.controller");
const controller_list = require("../controllers/list.controller");
const controller_delete = require("../controllers/delete.controller");
module.exports = function(app) {
app.use(function(req, res, next) {
res.header(
"Access-Control-Allow-Headers",
"x-access-token, Origin, Content-Type, Accept"
);
next();
});
app.post("/api/auth/donate", controller_donate.donate);
app.get("/api/auth/donate", controller_list.donations);
app.put("/api/auth/donate/update/:id", controller_receive.receive);
app.delete("/api/auth/donate/:id", controller_delete.delete);
};
delete.controller.js
const db = require("../models");
const Donate = db.donate;
const { donate } = require("../models");
exports.delete = (req, res) => {
const id = req.params.id;
donate.findByIdAndRemove(id)
.then(data => {
if (!data) {
res.status(404).send({ message: "Cannot delete item" });
} else {
res.status(200).send("This item is been redeemed");
}
})
}

Nestjs HttpService error handling with AxiosRequestConfig's validateStatus function

I need to handle http errors status code (such as 401, 500, etc) which can occur when consuming an external service using HttpService (HttpModule of Nestjs). Here is the implementation i am working on:
import { Injectable } from '#nestjs/common';
import { HttpService } from '#nestjs/axios';
import { Logger } from '#nestjs/common';
import { AxiosRequestConfig } from 'axios';
import { catchError, firstValueFrom, map } from 'rxjs';
type Person = {
name: string;
lastName: string;
};
#Injectable()
export class PersonService {
constructor(private httpService: HttpService) {}
async findPerson(): Promise<Person> {
const axiosConfig: AxiosRequestConfig = {
method: 'get',
url: 'https://service.dns/path/person',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${jwt}`,
},
validateStatus: function (status: number) {
return status === 200;
},
};
const personInstance: Person = await firstValueFrom(
this.httpService.request(axiosConfig).pipe(
catchError((e) => {
Logger.error(e.response.data.errorMessage);
throw new Error('internal communication error');
}),
map((res) => {
return res.data;
}),
),
);
return personInstance;
}
}
In the code above, I just need the function catchError throws the custom error, but I am not able to make the function validateStatus to trigger the execution of catchError.
I have implemented next code in order to take advantage of validateStatus function of AxiosRequestConfig for giving solution to my needs:
import { Injectable } from '#nestjs/common';
import { HttpService } from '#nestjs/axios';
import { Logger } from '#nestjs/common';
import { AxiosRequestConfig } from 'axios';
import { firstValueFrom } from 'rxjs';
type Person = {
name: string;
lastName: string;
};
#Injectable()
export class PersonService {
constructor(private httpService: HttpService) {}
async findPerson(): Promise<Person> {
const axiosConfig: AxiosRequestConfig = {
method: 'get',
url: 'https://service.dns/path/person',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer fake_jwt`,
},
validateStatus: function (status: number) {
return status === 200;
},
};
return firstValueFrom(this.httpService.request(axiosConfig))
.then((res) => res.data)
.catch((e) => {
Logger.error(e.errorMessage);
throw new Error('internal communication error');
});
}
}
Note: this code deals with Promise<AxiosResponse<any>> instead of Observable<AxiosResponse<any> methods

Status 400 sent from backend is not recognised as HttpResponse in the angular interceptor

I have http interceptor.
import { Injectable, Inject } from '#angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpResponse } from '#angular/common/http';
import { Router } from '#angular/router';
import { Observable } from 'rxjs';
import { tap } from "rxjs/operators";
import { ToastrService } from 'ngx-toastr';
import { NgxSpinnerService } from "ngx-spinner";
#Injectable()
export class AppHttpInterceptor implements HttpInterceptor {
constructor(
#Inject('API_URL') private baseUrl: string,
public router: Router,
public toasterService: ToastrService,
private spinner: NgxSpinnerService
) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// API url
request = request.clone({ url: `${this.baseUrl}/${request.url}` });
// notifications
return next.handle(request).pipe(
tap(evt => {
this.spinner.show();
if (evt instanceof HttpResponse && evt.body && typeof evt.body.success != "undefined") {
if(evt.body.success) {
this.spinner.hide();
this.toasterService.success(evt.body.message);
} else {
this.spinner.hide();
this.toasterService.error(evt.body.message);
}
} else {
this.spinner.hide();
}
})
);
}
}
there i am showing with toastr messages that are coming from backend, and if success is true then i show green toastr if false then red toastr indicating that something is wrong. And everything is good when the response status sent from nodejs backend api hosted on azure cloud is 200 ( the default one ).
context.res = {
body: { success: false, message: `Please add title field` }
};
The problem is if i send response with status 400 for example
context.res = {
status: 400,
body: { success: false, message: `Please add title field` }
};
then somehow the condition in mu http interceptor
evt instanceof HttpResponse
is not executed. But i don't know why. Why status code 400 is not instance of HttpReponse ?
return next.handle(req).pipe(
tap(
(res: any) => {// success block},
(error: any) => {// error block}
)
);
I do this in my app, you could probably achieve the same thing with the filter rxjs operator.
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 400) {
// Do something
}
})
);

how to read property 'subscribe' of undefined?

I have created a MEAN stack application which does the basic job of inserting,delete,update and viewing the data from mongoDB.
first of all i cloned this MEAN stack application from github. the application was based on the employee, but i renamed all the components, routing, etc from 'employee' to 'sensor'. what i have done literally is changed the word 'employee' to 'sensor'.
and i had not issues in compiling the code.
the build was successful.
but when i launched localhost:4200 , the first page was displayed properly,which is insert component. the data is inserted into mongodb. so this component has no issues.
but when i click on view sensor component,it shows a blank page.
so when i checked on chrome console by clicking on f12,it showed a list of errors.
please check for the errors in the below screenshot.4
the service.api code is below
import { Injectable } from '#angular/core';
import { throwError } from 'rxjs';
import { Observable } from 'rxjs/Observable';
import { catchError, map } from 'rxjs/operators';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ApiService {
baseUri:string = 'http://localhost:4000/api';
headers = new HttpHeaders().set('Content-Type', 'application/json');
getSensors: any;
constructor(private http: HttpClient) { }
// Create
createSensor(data): Observable<any> {
let url = `${this.baseUri}/create`;
return this.http.post(url, data)
.pipe(
catchError(this.errorMgmt)
)
}
// Get Sensor
getSensor(id): Observable<any> {
let url = `${this.baseUri}/read/${id}`;
return this.http.get(url, {headers: this.headers}).pipe(
map((res: Response) => {
return res || {}
}),
catchError(this.errorMgmt)
)
}
// Update Sensor
updateSensor(id, data): Observable<any> {
let url = `${this.baseUri}/update/${id}`;
return this.http.put(url, data, { headers: this.headers }).pipe(
catchError(this.errorMgmt)
)
}
// Delete Sensor
deleteSensor(id): Observable<any> {
let url = `${this.baseUri}/delete/${id}`;
return this.http.delete(url, { headers: this.headers }).pipe(
catchError(this.errorMgmt)
)
}
// Error handling
errorMgmt(error: HttpErrorResponse) {
let errorMessage = '';
if (error.error instanceof ErrorEvent) {
// Get client-side error
errorMessage = error.error.message;
} else {
// Get server-side error
errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
}
console.log(errorMessage);
return throwError(errorMessage);
}
}
SENSOR-LIST.COMPONENT.TS is below
import { Component, OnInit } from '#angular/core';
import { ApiService } from './../../service/api.service';
#Component({
selector: 'app-Sensor-list',
templateUrl: './Sensor-list.component.html',
styleUrls: ['./Sensor-list.component.css']
})
export class SensorListComponent implements OnInit {
Sensor: any = [];
constructor(private apiService: ApiService) {
this.readSensor();
}
ngOnInit() {}
readSensor() {
this.apiService.getSensors.subscribe ((data) => {
this.Sensor = data;
});
}
removeSensor(Sensor, index) {
if (window.confirm('Are you sure?')) {
this.apiService.deleteSensor(Sensor._id).subscribe((data) => {
this.Sensor.splice(index, 1);
}
);
}
}
}
some of the screenshots
img 12
img 23
img 34
please help me out in this problem
getSensors is not a function first of all. You declared it in ApiService as a variable of type any. So if you want the list of sensors. Create the getSensors() method which will allow you to retrieve the list of sensors via the URL intended for it

GET Request 401 (Unauthorized)

In Postman the profile is authorized and a json object is returned.
But on the front-end, I'm getting this error.
HttpErrorResponse {headers: HttpHeaders, status: 401, statusText: "Unauthorized", url: "http://localhost:3000/users/profile", ok: false, …}
Here is my auth.service.ts file:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable, Subject } from 'rxjs';
import 'rxjs/add/operator/map';
interface data{
success: boolean;
msg: string;
token: string;
user: any;
}
export class AuthService {
authToken: any;
user: any;
constructor(private http: HttpClient) { }
getProfile() {
let headers = new HttpHeaders();
this.loadToken();
headers.append('Authorization', this.authToken);
headers.append('Content-Type', 'application/json');
return this.http.get<data>('http://localhost:3000/users/profile', {headers: headers})
.map(res => res);
}
loadToken(){
const Token = localStorage.getItem('id_token');
this.authToken = Token;
}
}
profile.ts file:
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: Object;
constructor(
private authService: AuthService,
private router: Router,
) { }
ngOnInit() {
this.authService.getProfile().subscribe(profile => {
this.user = profile.user;
},
err => {
console.log(err);
return false;
});
}
}
this is happening because this.loadToken() returns you the token. you have to wait till you this.loadToken() function returns you the authToken.
for this, you can use async and await for your function or else just return the value from this.loadToken like
getProfile() {
let headers = new HttpHeaders();
this.authToken = this.loadToken();
headers.append('Authorization', this.authToken);
headers.append('Content-Type', 'application/json');
return this.http.get<data>('http://localhost:3000/users/profile', {headers: headers})
.map(res => res);
}
loadToken(){
const Token = localStorage.getItem('id_token');
return Token;
}
Not sure this will help but try to enable CORS in your WebAPI project:
WebApiConfig.cs (Register Method):
EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);

Resources