Express Send data via request body but request methode is GET? - mysql

Hey there It's my first post so sorry if I am doing something wrong here but be patient with me ;)
I am trying to send some data in JSON format to my MySQL DB using Express but whenever I use something else besides app.get() it fails. I guess it is because the request methode shown in the browser is always GET but I dont know why.
What am I doing wrong? How can the request method be GET when I am using app.post()?
const express = require('express');
const mysql = require('mysql');
const bodyParser = require('body-parser');
const db = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'masterkey',
database: 'articelStorage'
});
const app = express();
app.use(bodyParser.json());
app.use(express.json());
//connect to db
db.connect((err) => {
if (err) {
throw err;
}
console.log('Myql connected...');
});
app.listen('3000', () => {
console.log('Server started and running on port 3000...');
});
app.get('/getOne/:code', (req, res) => {
let sql = "SELECT * FROM articels WHERE acode ='" +req.params.code+"'";
db.query(sql, (err, result) => {
if (err) throw err;
res.send(result);
});
});
app.delete('/deleteOne/:code', (req, res) => {
let sql = "DELETE FROM articels WHERE acode ='" +req.params.code+ "'";
db.query(sql, (err, result) => {
if (err) throw err;
res.send(result);
});
});
Here is the result I get:
Cannot GET /deleteOne/DE12345678
And the Headers:
General:
Request URL: http://localhost:3000/deleteOne/DE12345678
Request Method: GET
Status Code: 404 Not Found
Remote Address: [::1]:3000
Referrer Policy: no-referrer-when-downgrade
Response Headers:
Connection: keep-alive
Content-Length: 159
Content-Security-Policy: default-src 'self'
Content-Type: text/html; charset=utf-8
Date: Thu, 07 Mar 2019 13:12:36 GMT
X-Content-Type-Options: nosniff
X-Powered-By: Express
Request Headers:
Accept: text/html,application/xhtml+xml,application/xml;
q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Host: localhost:3000
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36
Thx in advance.

I think there is a misconception here.
When you are declaring app.get('/getOne/:code', (req, res)=>{..}) it means the route is accessible by HTTP GET. Similarly for app.delete the route is accessible by request method HTTP DELETE.
Now, when you open a url in browser it is ALWAYS a HTTP GET request. That's why the /getOne will work, but not the delete one.
You need to use Postman(or curl) like application to test your REST api.
If you are accessing an endpoint from Client, use axios or request or xmlhttprequest and set the request method what you want it to be.
For example,
axios({url:url, method:'delete', { data: { foo: "bar" } });// or axios.delete(..)

Related

Node.js scraping with the request module

I want to get html from a web. But it show like that.
meta http-equiv=refresh content="0;url=http://www.skku.edu/errSkkuPage.jsp">
But when I use https://www.naver.com/ instead of https://www.skku.edu/skku/index.do, it works well.
I want to know the reason.
Here's my code.
var request = require('request');
const url = "https://www.skku.edu/skku/index.do";
request(url, function(error, response, body){
if (error) throw error;
console.log(body);
});
The website blocks the request that is coming from programmatic script checking User-Agent in the request header.
Pass the user-Agent that web-browser(eg: Google chrome) sends and it should work.
var request = require('request');
var options = {
'method': 'GET',
'url': 'https://www.skku.edu/skku/index.do',
'headers': {
'User-Agent': ' Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
I wouldn't recommend request module as it is not maintained for changes anymore. see it here - https://github.com/request/request/issues/3142
You could look for alternatives in form of got, axios etc which makes code much more readable and clear. And most important thing - Native support for promises and async/await The above code will look like
var got = require('got');
const url = "https://www.skku.edu/skku/index.do";
(async () => {
const response = await got(url);
console.log(response.body);
})();

React app receiving promise instead of json object

I am trying to query an API that should return a json object of books that match a user's query.
The problem is what I am getting in the code is a promise rather than teh json object.
In the Chrome dev tools I can see I am getting a 200 response from the server with a Type of json and the object there is what I am expecting to receive.
When I console.log the result of the query it comes up as a promise though.
Pretty new to this but my understanding is that I should be getting a json object when searchBook is set with a query string in my SearchBooks component
SearchBooks.js
import React, { Component } from 'react'
import * as BooksAPI from './utils/BooksAPI'
// import Book from './Book';
export default class SearchBooks extends Component {
state = {
query: ''
}
updateQuery = (query) => {
this.setState(() => ({
query: query
}))
}
clearQuery = () => {
this.updateQuery('')
}
searchBook = (query) => {
return BooksAPI.search(query)
}
searchFromQuery = () => {
return this.state.query.split(' ').map((b) => (
this.searchBook(b)
))
}
render() {
const { query } = this.state
// const { onUpdateShelf } = this.props
const showingBooks = query === ''
? 'No results'
: this.searchFromQuery()
return(
<div className="search-books">
<div className="search-books-bar">
<a className="close-search" >Close</a>
<div className="search-books-input-wrapper">
<input
type="text"
placeholder="Search by title, author or subject"
value={query}
onChange={(event) => this.updateQuery(event.target.value)}
/>
</div>
</div>
<div className="search-books-results">
<ol className="books-grid">
{/* <Book
key={book.id}
book={book}
updateShelf={onUpdateShelf} /> */}
</ol>
</div>
</div>
)
}
}
API Request Function
export const search = (query) =>
fetch(`${api}/search`, {
method: 'POST',
headers: {
...headers,
'Content-Type': 'application/json'
},
body: JSON.stringify({ query })
}).then(res => res.json())
.then(data => data.books)
Result of console.log(this.searchFromQuery())
[Promise]
0
:
Promise
__proto__
:
Promise
[[PromiseStatus]]
:
"resolved"
[[PromiseValue]]
:
Array(20)
length
:
1
__proto__
:
Array(0)
Request/Response Headers
// Request
POST /search HTTP/1.1
Host: reactnd-books-api.xxxxx
Connection: keep-alive
Content-Length: 13
Accept: application/json
Origin: http://localhost:3000
Authorization: 2nhixsfp
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Content-Type: application/json
Referer: http://localhost:3000/search
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
// Response
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
ETag: W/"78c1-CfIO/Nda/QZYUxfCqeekUjLL3SU"
Date: Wed, 23 May 2018 15:15:00 GMT
Transfer-Encoding: chunked
Content-Encoding: gzip
X-Berlioz-Country: GB
Access-Control-Allow-Headers: X-Berlioz-Country
Access-Control-Expose-Headers: X-Berlioz-Country
Strict-Transport-Security: max-age=300;
Request URL: https://xxxx.com/search
Request Method: POST
Status Code: 200 OK
Remote Address: xxxxx
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Headers: X-Berlioz-Country
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-Berlioz-Country
Content-Encoding: gzip
Content-Type: application/json; charset=utf-8
Date: Wed, 23 May 2018 15:15:00 GMT
ETag: W/"78c1-CfIO/Nda/QZYUxfCqeekUjLL3SU"
Strict-Transport-Security: max-age=300;
Transfer-Encoding: chunked
X-Berlioz-Country: GB
X-Powered-By: Express
Accept: application/json
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Authorization: 2nhixsfp
Connection: keep-alive
Content-Length: 13
Content-Type: application/json
Host: reactnd-books-api.udacity.com
Origin: http://localhost:3000
Referer: http://localhost:3000/search
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
{query: "p"}
query
:
"p"
Calling res.json() on a response from fetch returns a promise that resolves to the body of the request in JSON format. What you should do is setting some state with the data coming from the request. You can do it this way:
export default class SearchBooks extends Component {
state = {
query: '',
books: []
}
updateQuery = (query) => {
this.setState(() => ({
query: query
}))
}
clearQuery = () => {
this.updateQuery('')
}
searchBook = (query) => {
// Instead of returning the promise, you add the response data to the state
BooksAPI.search(query)
.then(books => this.setState(prevState => ({ books: prevState.books.concat(books)})));
}
render() {
const { query } = this.state
// const { onUpdateShelf } = this.props
const showingBooks = query === ''
? 'No results'
: this.searchBook(query)
return(
<div className="search-books">
<div className="search-books-bar">
<a className="close-search" >Close</a>
<div className="search-books-input-wrapper">
<input
type="text"
placeholder="Search by title, author or subject"
value={query}
onChange={(event) => this.updateQuery(event.target.value)}
/>
</div>
</div>
<div className="search-books-results">
<ol className="books-grid">
{this.state.books.map(book => <Book key{book.id} book={book} updateShelf={onUpdateShelf} />)}
</ol>
</div>
</div>
)
}
}
This is the general idea, just take the value from the promise and set it to the state. You can expand on this as needed.

"XML Parsing Error: no root element found" Ionic/Angular

There are many topics with this similar error: "XML Parsing Error: no root element found", but none of them cover the error for Ionic framework.
I am writing an app with Ionic framework, and this is the function to POST the data:
http.ts
postData(url, body) {
const headers = new Headers();
headers.append('Content-Type', 'application/json');
const result = this.http.post(url, JSON.stringify(body), {headers: headers})
.map(response => {
console.log(response.json());
response.json();
})
.subscribe(data => {
console.log(typeof(data));
console.log("subscribe data");
},
error => {
console.log(error.statusText);
})
A button on my app's HTML form calls the onSubmit function to send the data like below.
submit.ts
onSubmit() {
var submitData = {
'customer': {
'phone_number': this.clientInfo.phone,
'name': this.clientInfo.name
},
'amount': this.clientInfo.amount
}
const submitResult = this.httpProvider.postData(postTransactionsURL, submitData);
Now, on Firefox, this is the error that is shown in the console:
XML Parsing Error: no root element found
Location: http://localhost:3000/transactions
Line Number 1, Column 1:
As reported in other posts, the error does not show up on e.g. Edge, but nevertheless, there is still a more generic error.
Is there anything I could try to resolve this? I would assume the header is correct for this?
Update: added POST network information from console:
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 0
Date: Fri, 02 Mar 2018 12:42:36 GMT
X-Powered-By: Express
Update2: server.js response
app.post('/transactions', (req, res) => {
......
......
......
res.status(200).send();
} else {
res.status(400).send("Invalid transaction");
}
});

angular - make it to call api that accept json format

I am very new to angularjs.
I am trying to make the http call and posting object to the api which only accept json.
'use strict';
// Declare app level module which depends on views, and components
var app = angular.module('ngShow', ['ngRoute','ngResource']);
app.
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/login', {templateUrl: 'partials/login.html' });
$routeProvider.otherwise({redirectTo: '/login'});
}]);
app.
config(['$httpProvider', function($httpProvider) {
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common['Access-Control-Max-Age'] = '1728000';
$httpProvider.defaults.headers.common['Accept'] = 'application/json, text/javascript';
$httpProvider.defaults.headers.common['Content-Type'] = 'application/json; charset=utf-8';
$httpProvider.defaults.useXDomain = true;
}]);
but seems doesn't work from the request headers.
Request Headers 15:31:10.000
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0
Pragma: no-cache
Origin: http://localhost:63342
Host: localhost:8080
DNT: 1
Connection: keep-alive
Cache-Control: no-cache
Access-Control-Request-Method: POST
Access-Control-Request-Headers: access-control-max-age
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
UPDATE #001
Added my loginService.js - it is calling the api ok but just not the json.
app.factory('loginService', function($http){
return{
login:function(user){
console.log("enter login service");
var $promise=$http.post('http://localhost:8080/api/login',user); //send data to the api
$promise.then(function(msg){
if(msg.data=='succes') console.log('succes login');
else console.log('error login');
});
}
}
});
I've got following concerns here:
You use 2 config sections for one module. Not sure if this approach is expected.
Accordingly the documentation, such params are set in run section
Assuming that the user param in the login() method of your loginService factory is the object you want to send as your JSON payload, you can try the following:
var payload = JSON.stringify(user);
var promise = $http({
url: '/api/login',
method: 'POST',
data: payload,
headers: {'Content-Type': 'application/json'}
});
promise.then(function(...) {
...
});
UPDATE:
I would also consolidate the two .config() calls in your code.
app.config(['$routeProvider', '$httpProvider', function($routeProvider, $httpProvider) {
$routeProvider.when('/login', {templateUrl: 'partials/login.html' });
$routeProvider.otherwise({redirectTo: '/login'});
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common['Access-Control-Max-Age'] = '1728000';
$httpProvider.defaults.headers.common['Accept'] = 'application/json, text/javascript';
$httpProvider.defaults.headers.common['Content-Type'] = 'application/json; charset=utf-8';
$httpProvider.defaults.useXDomain = true;
}]);
You're already setting the Content-Type header globally (i.e. for all requests) using $httpProvider.defaults.headers.common['Content-Type'], so the headers: {'Content-Type': 'application/json'} in my code above is redundant.

Restangular won't change Http Content-Type

In order to send a file as part of my form, I changed the content type to "multipart/form-data", but when I check the console, it's still using application/json;charset=utf-8 And Node.js (with Sails.js framework) prints an error saying it's invalid JSON.
Here is the code:
$rootScope.objects.user.withHttpConfig({
transformRequest: angular.identity
}).customPUT($scope.objects.user, "", { // user object contains a file
'Content-Type': "multipart/form-data" // should change content-type. I've tried using `undefined` as well
}).then(function(resp) {
if (resp == "OK") {
$scope.successes = [{
msg: "Saved"
}];
}
}, function(err) {
console.log(err);
$scope.errors = err.data.errors;
});
The "Inspect Network Request" tab in Google Chrome reads:
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:30.0) Gecko/20100101 Firefox/30.0
Referer: http://localhost:1337/user/settings
Host: localhost:1337
DNT: 1
Content-Type: application/json;charset=utf-8
Content-Length: 505679
Connection: keep-alive
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Accept: application/json, text/plain, */*
As said in comment above and According to docs you should pass headers as fourth parameter. So your code should be
$rootScope.objects.user.withHttpConfig({
transformRequest: angular.identity
}).customPUT(
$scope.objects.user,
undefined,
undefined,
{
'Content-Type': "multipart/form-data"
}
).then(function(resp) {
if (resp == "OK") {
$scope.successes = [{
msg: "Saved"
}];
}
}, function(err) {
console.log(err);
$scope.errors = err.data.errors;
});
Reference url : https://github.com/mgonto/restangular#custom-methods