Returning API response rather than data - javascript

I have been staring at this for a while, and finally realized that my code is returning the "200 ok." response instead of the actual data itself, and that is why it won't populate my ionic buttons. When I am calling the API via postman, and printing it to the console it is showing the data that I need, so I am assuming the issue is somewhere in the .ts files.
Below is my API code:
app.get('/getAllProvs', function (req,res) {
//var id = req.params.id;
connection.query('SELECT * from Patient', function(err, rows, fields) {
if (!err){
var response = [];
if (rows.length != 0) {
response.push({'result' : 'success', 'data' : rows});
} else {
response.push({'result' : 'error', 'msg' : 'No Results Found'});
}
res.setHeader('Content-Type', 'application/json');
//res.status(200).send(JSON.stringify(rows));
res.send(rows);
console.log(rows);
} else {
res.status(400).send(err);
}
});
});
below is my provider .ts code:
export class RestService {
data1: any;
constructor(public http: Http) {
console.log('Hello RestServiceProvider Provider');
}
getAllProvs(){
if(this.data1){
return Promise.resolve(this.data1);
}
return new Promise(resolve => {
this.http.get('http://lndapp.wpi.edu:5000/getAllProvs')
.map(res => res.json())
.subscribe(data => {
console.log("rest-services.ts subscribe");
this.data1 = data;
console.log(data);
resolve(this.data1);
});
});
}
}
below is my page .ts file:
export class AllPatientsPage {
data1: any;
constructor(public app: App, public loadingCtrl: LoadingController, private toastCtrl: ToastController, public navCtrl: NavController, public restService: RestService){
this.getAllProvs();
}
}
getAllProvs(){
this.restService.getAllProvs()
.then(data => {
console.log("all-patients.ts data");
console.log(data);
this.data1 = data;
}).catch(e => {
console.log(e);
});
}
}

Send a json response from your service:
res.json(rows);

If this is happening during development, it could be because you're using the same url on your front end react website as your server.js site.
Example:
front end running on : localhost:3000
backend listening on : localhost:3000/api
Fix: Change the port numbers.
front end running on : localhost:3000
backend listening on : localhost:5000/api
Additional help:
package.json: add proxy that points to your server: localhost:5000
browser: clear your cookies.
Hope this helps.

Related

Angular await service between components, Behavior Subject

I have an issue in my Angular web store when i refresh the window, i create a service that takes the user data from the server and then inject to the 'products' section with BehaviorSubject, my goal is to make just one request to the server:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable({
providedIn: 'root'
})
export class DataService {
private userId = new BehaviorSubject<any>('');
currentUserId = this.userId.asObservable();
constructor() { }
sendUserId(message: string){
this.userId.next(message)
}
}
This works fine but the problem is when i refresh the window in products section, in console i can see that the service takes the user data but when i getProducts() it throws an error, it seems like getProducts() makes the request before the service had the response, i need the user Id to make the products request. My question: Is there a way to await the response of BehaviorSubject and then make the getProducts() request?. This is the code in the products section:
ngOnInit(): void {
this._dataService.currentUserId.subscribe(userId => this.userId = userId);
if(this.userId.length === 0){
this.userService.getUserProfile().subscribe(
res => {
this.userDetails = res['user'];
this.userId = this.userDetails._id;
this.getProducts();
},
err => {
console.log(err);
}
);
} else {
this.getProducts();
}
}
As you can see, i do a condition to check if userId exists, if not i have to make a new user request, this fix the bug but i think there's a better way to solve this. Thanks in advance.
How about placing all your logic within the observer's next function as below:
this._dataService.currentUserId.subscribe(userId => {
if (userId.length === 0)
{
this.userService.getUserProfile().subscribe(
res => {
this.userDetails = res['user'];
this.userId = this.userDetails._id;
this.getProducts();
},
err => {
console.log(err);
}
);
} else
{
this.getProducts();
}
});

Simple post request to get location

I am trying to get the location of a user and send it to my server so I can make some api calls. I get the current location of the user, which is fine, but it does not post to the server and I do not know why. Can you look at my code and help me figure it out.
Backend
index.routes.js
router.post('/currentLatLong', ctrlEvent.currentLatLong);
event.controller.js
module.exports.currentLatLong = (req, res) => {
console.log('recieved');
this.currentLoc = req.body;
console.log('this.currentLoc', this.currentLoc);
}
Front-end
Service
constructor(private data: DataService, private http: HttpClient) { }
getUserLocation() {
/* locate the User */
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => {
this.currentLat = position.coords.latitude;
this.currentLng = position.coords.longitude;
console.log('position.coords.latitude', this.currentLat);
this.data.latitudeSource.next(this.currentLat);
this.data.longitudeSource.next(this.currentLng);
const currentLatLong = {
latitude: this.currentLat,
longitude: this.currentLng
};
console.log('currentLatLong', currentLatLong);
return this.http.post(environment.apiBaseUrl + '/currentLatLong',
currentLatLong);
}, err => {
console.log(err);
return false;
});
} else {
console.log('bad');
return false;
}
}
In angular side, you need to call the subscribe() method. Calling the subscribe() method executes the observable, which is what initiates the request.
this.http.post(environment.apiBaseUrl + '/currentLatLong', currentLatLong)
.subscribe(
res => {
console.log(res);
},
err => {
console.log(err);
}
);
An HttpClient method does not begin its HTTP request until you call subscribe() on the observable returned by that method.

subscribing in Angular

I am completely new to Angular and I've created a project using SpringBoot 2.0.5.RELEASE, Angular 5 and spring data to build an end to end single page java web application. I use spring boot 1.5 to expose REST APIs and angular5 with routing to build the client that will consume the APIs exposed by the server.
I've defined this component:
import { Component } from '#angular/core';
import { Router } from '#angular/router';
import { User } from '../models/user.model';
import { UserService } from './user.service';
#Component({
templateUrl: './add-user.component.html'
})
export class AddUserComponent {
user: User = new User();
constructor(private router: Router, private userService: UserService) {
}
createUser(): void {
alert ('lala');
this.userService.createUser(this.user)
.subscribe( data => {
alert('User created successfully.');
});
}
}
in the page I can see the alert lala, but not 'User created successfully.' but I have no idea why
The link address when I create a user is this is this one http://localhost:4200/api/users
This is my proxy.config.json file:
{
"/api/*": {
"target": "http://localhost:8080/user-portal",
"secure": false
}
}
and from curl is fine :
curl -X POST -H "Content-Type: application/json" "http://localhost:8080/user-portal/api/users"
and user.service.ts:
import {Injectable} from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { User } from '../models/user.model';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
#Injectable()
export class UserService {
constructor(private http: HttpClient) {}
private userUrl = '/api/users';
public getUsers() {
return this.http.get<User[]>(this.userUrl);
}
public deleteUser(user) {
return this.http.delete(this.userUrl + '/'+ user.id);
}
public createUser(user) {
return this.http.post<User>(this.userUrl, user);
}
}
Firstly, best not to use alert. Use console.log. Secondly, you are only handling success, you are not handling failure. Do this:
createUser(): void {
console.log('lala');
this.userService.createUser(this.user)
.subscribe(data => {
console.log('User created successfully', data);
},
err => {
console.log('There was an error', err);
},
() => {
console.log('I have completed now and nothing will ever be emitted from this Observable again');
});
}
The error handler will be executed if the HTTP response is not a success response, viz if the status code of the response is not in the 2xx range.
Check your browser network tab also to see if the HTTP request is failing.
You prob also want to debug this:
public createUser(user) {
console.log('userUrl', this.userUrl)
console.log('user', user)
return this.http.post<User>(this.userUrl, user);
}
To make sure all is as expected.
In Chrome hit F12 to open the dev tools and go to the network tab. Make sure that a request is being made to the end point and that it is not throwing and error.

Angular Http.get request from servlet of project on local server (json data returns correctly, but not displaying, does work with a mock api)

Error in console:
Error with getting users from service. Response with status: 404 Not Found for URL: http://localhost:8080/ChatApp/GetAllUsersServlet
Same problem occurs when I deployed the external project somewhere, so with url:
http://java.cyclone2.khleuven.be:38034/ChatApp/GetAllUsersServlet
You can see for yourself is a working url with json in it, but stil 404 error.
Angular code expecting json from servlet running on local server:
export class UserService {
// private usersUrl = 'api/users'; // mock api
private usersUrl = 'http://localhost:8080/ChatApp/GetAllUsersServlet'; // external users from local server
private headers = new Headers({'Content-Type': 'application/json'});
constructor(private http: Http) { }
getUsers(): Promise<User[]> {
return this.http.get(this.usersUrl)
.toPromise() // Http.get returns RxJS Observeable, converted to Promise here
.then(response => response.json().data as User[]) // .data for mock inMemoryDataService
.catch(this.handleError);
}
What Servlet returns:
[{"fname":"TestFname","password":"test","gender":"Female","name":"TestName","id":1,"email":"test#test.com","age":21,"username":"Test","status":"offline"},{"fname":"Test4Fname","password":"test","gender":"Female","name":"Test4Name","id":4,"email":"test4#test.com","age":21,"username":"Test4","status":"offline"},{"fname":"Test3Fname","password":"test","gender":"Female","name":"Test3Name","id":3,"email":"test3#test.com","age":28,"username":"Test3","status":"offline"},{"fname":"Test2Fname","password":"test","gender":"Male","name":"Test2Name","id":2,"email":"test2#test.com","age":22,"username":"Test2","status":"offline"}]
This exact thing in a mock api, does give correct result:
import { InMemoryDbService } from 'angular-in-memory-web-api';
export class InMemoryDataService implements InMemoryDbService {
createDb() {
let users = [{"fname":"TestFname","password":"test","gender":"Female",
"name":"TestName","id":1,"email":"test#test.com","age":21,"username":"Test","status":"offline"},
{"fname":"Test4Fname","password":"test","gender":"Female",
"name":"Test4Name","id":4,"email":"test4#test.com","age":21,"username":"Test4","status":"offline"},{"fname":"Test3Fname","password":"test","gender":"Female","name":"Test3Name","id":3,"email":"test3#test.com","age":28,"username":"Test3","status":"offline"},
{"fname":"Test2Fname","password":"test","gender":"Male",
"name":"Test2Name","id":2,"email":"test2#test.com","age":22,"username":"Test2","status":"offline"}]
return {users};
}
}
Any help would be appreciated, since I really don't know why it won't work. Tried something similar but just less json data and that works.
Yes, the server for the servlet is running locally.
getUsers() gets used and displayed by this, but since it works with mock data, this should be okay?:
export class UsersComponent {
users: User[];
selectedUser: User;
constructor(
private userService: UserService,
private router: Router) { }
gotoInfo(): void {
this.router.navigate(['/info', this.selectedUser.username]);
}
onSelect(user: User): void {
this.selectedUser = user;
}
getUsers(): void {
this.userService.getUsers().then(users => this.users = users);
}
ngOnInit(): void {
this.getUsers();
}
}
Servlet (cors enabled):
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
UserDB db = new UserDB();
JSONArray array = new JSONArray();
for (User users: db.getAll()) {
try {
array.put(users.getJSONObject());
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// setting the response type to json
response.setContentType("application/json");
// setting the CORS request
response.setHeader("Access-Control-Allow-Origin", "*");
response.getWriter().write(array.toString());
Previously using in-memory-web-api will mess with your http-requests unless you remove something like the following InMemoryWebApiModule.forRoot(InMemoryDataService) from your NgModule, then your requests should be going fine.
EDIT: Realized based on code comment that you knew the following:
After this is done, I can also point out that you have a problem in your get request, as it stands you will not get any data in your component. Your response just contains an array, not data, so it should be just:
.then(response => response.json() as User[])

Angular 2 HTTP GET to Node backend for list of file names in directory

I'm trying to use an Angular 2 HTTP GET request to simply connect with a Node/Express backend that responds with a list of the file names in a certain folder using the fs.readdir method.
I set up the Angular 2 request as a service:
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import './rxjs-operators';
#Injectable()
export class PhotoService {
constructor (private http: Http) {}
private photosUrl = '/api/photos'; // URL to web API
getPhotos() : Observable<string[]> {
return this.http.get(this.photosUrl)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body.data || { };
}
private handleError (error: any) {
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);
}
}
and then called this service from a component:
ngOnInit() {
this.photoService.getPhotos()
.subscribe(
photos => this.fileList = photos,
error => this.errorMessage = <any>error);
}
This is the Node backend (with Express set up as per conventions):
//Photo Service
app.get('/api/photos', function(req, res) {
fs.readdir('./uploads', function(error, files) {
if (error) {
throw error;
}
else {
res.end(files);
}
});
});
As seen, the HTTP request calls a GET method to http://localhost:3000/api/photos and the Node backend is supposed to receive that request and send back an array of strings that have the names of files in the 'uploads' folder.
However it does not seem to be working. I think I'm getting confused with the format in which the Node API sends the response and how that works with the Observable type that Angular uses in the service.
Your Angular 2 code looks good to me. But in your Node backend you should not send data with res.end() (see the documentation). Correct would be res.send(files); or in your case res.json(files); which will also set the right Content-Type header.

Categories