Pending promise state using javascript fetch api with java spark (POST request) - javascript

I am trying to use ES6's fetch api to post some login data to a java spark server. The GET requests work perfectly, but when I try to POST something, the Promise on the client side stays 'pending'. I checked, and the server receives the request body, and parses it to an object. Using postman, it also returns true or false, so I think something is wrong with the CORS setup. I'm new to that, so i jut let * through, thinking it should work. I am using VueJS, but i don't think that really matters here, thought I'd add this info, maybe it helps. I will post the code below.
JS:
methods: {
login: function () {
data = '"perfectly valid json string"'
this.postData('http://te.st/login', data)
},
postData: function(url, data){
return fetch(url, {
body: data,
method: 'POST',
})
.then(response => response.json())
.then(function (result){
app.response = result
})
}
}
Java:
private static void enableCORS(final String origin, final String methods, final String headers) {
options("/*", (request, response) -> {
String accessControlRequestHeaders = request.headers("Access-Control-Request-Headers");
if (accessControlRequestHeaders != null) {
response.header("Access-Control-Allow-Headers", accessControlRequestHeaders);
}
String accessControlRequestMethod = request.headers("Access-Control-Request-Method");
if (accessControlRequestMethod != null) {
response.header("Access-Control-Allow-Methods", accessControlRequestMethod);
}
return "OK";
});
before((request, response) -> {
response.header("Access-Control-Allow-Origin", origin);
response.header("Access-Control-Request-Method", methods);
response.header("Access-Control-Allow-Headers", headers);
response.type("application/json");
});
}
(called in the code as enableCORS("*","GET,POST","Origin, Content-Type, Access-Control-Allow-Origin"); )
And the endpoint:
post("/login", (req, res) -> {
boolean ret = dao.checkLogin(gson.fromJson(req.body(), User.class));
return gson.toJson(ret);
});

Related

Forward body from request to another url

I am wondering if someone might be able to help figure out how to pass a post body to another endpoint with cloudflare workers?
I am trying to get the incoming request post to post to url.
const url = 'https://webhook.site/#!/b2f75ce2-7b9e-479a-b6f0-8934a89a3f3d'
const body = {
results: ['default data to send'],
errors: null,
msg: 'I sent this to the fetch',
}
/**
* gatherResponse awaits and returns a response body as a string.
* Use await gatherResponse(..) in an async function to get the response body
* #param {Response} response
*/
async function gatherResponse(response) {
const { headers } = response
const contentType = headers.get('content-type') || ''
if (contentType.includes('application/json')) {
return JSON.stringify(await response.json())
} else if (contentType.includes('application/text')) {
return response.text()
} else if (contentType.includes('text/html')) {
return response.text()
} else {
return response.text()
}
}
async function handleRequest() {
const init = {
body: JSON.stringify(body),
method: 'POST',
headers: {
'content-type': 'application/json;charset=UTF-8',
},
}
const response = await fetch(url, init)
const results = await gatherResponse(response)
return new Response(results, init)
}
addEventListener('fetch', (event) => {
return event.respondWith(handleRequest())
})
I created a worker at https://tight-art-0743.ctohm.workers.dev/, which basically forwards your POST request's body to a public requestbin. You can check what is it receiving at: https://requestbin.com/r/en5k768mcp4x9/24tqhPJw86mt2WjKRMbmt75FMH9
addEventListener("fetch", (event) => {
event.respondWith(
handleRequest(event.request).catch(
(err) => new Response(err.stack, { status: 500 })
)
);
});
async function handleRequest(request) {
let {method,headers}=request,
url=new URL(request.url)
// methods other than POST will return early
if(method!=='POST') return new Response(`Your request method was ${method}`);
const forwardRequest=new Request("https://en5k768mcp4x9.x.pipedream.net/", request)
forwardRequest.headers.set('X-Custom-Header','hey!')
return fetch(forwardRequest)
}
You can see it working with a simple CURL request
curl --location --request POST 'https://tight-art-0743.ctohm.workers.dev/' \
--header 'Content-Type: application/json' \
--data-raw '{"environment": {"name": "Sample Environment Name (required)"}}'
Two things worth noting, in the worker's code:
I'm passing the original request as the init parameter, through which original headers and body are transparently forwarded to the requestbin, also allowing for some extra header manipulation if neeeded.
In this example I'm not actually doing anything with the request body. Therefore there's no need to await it. You just connect incoming and outgoing streams and let them deal with each other.
Another example: let's add a /csv route. Requests starting with /csv will not forward your POST body. Instead they will download a remote CSV attachment and POST it to the requestbin. Again, we aren't awaiting for the actual CSV contents. We pass a handle to the response body to the forwarding request
async function handleRequest(request) {
let {method,headers}=request,
url=new URL(request.url)
if(method!=='POST') return new Response(`Your request method was ${method}`);
const forwardRequest=new Request("https://en5k768mcp4x9.x.pipedream.net/",request)
if(url.pathname.includes('/csv')) {
const remoteSource=`https://cdn.wsform.com/wp-content/uploads/2018/09/country_full.csv`,
remoteResponse=await fetch(remoteSource)
return fetch(forwardRequest,{body:remoteResponse.body})
}
forwardRequest.headers.set('X-Custom-Header','hey!')
return fetch(forwardRequest)
}
While your code should theoretically work, the fact that you're unwrapping the response means your worker could be aborted due to hitting time limits, or CPU, or memory. On the contrary, when using the streams based approach,
your worker's execution finishes as soon as it returns the forwarding fetch. Even if the outgoing POST is still running, this isn't subject to CPU or time limits.

React button connection with database through axios.post()

I have 4 inputs and button which takes all data from them and sends to my PostreSQL database through axios.post() request. Not clearly understand how .then() is working. So, here is my button code which just calls this.addNewPainting function:
<button onClick={ this.addNewPainting }>Submit</button>
Here is my addNewPainting function:
addNewPainting() {
axios.post(`http://localhost:333/api/add`, {
title: this.state.titleInput,
year: this.state.yearInput,
size: this.state.yearInput,
location: this.state.locationInput
})
.then(function(response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
Before this project, I used to put response.data to the array with this.setState, but now I have the database and I'm just stuck.
Here is my controller function:
add_painting: (req, res, next) => {
const db = req.app.get('db');
const { title, year, size, location } = req.body;
console.log(title, year, size, location);
db.add_painting([ title, year, size, location ])
.then( () => res.status(200).send() )
.then( () => res.status(500).send() );
}
And the endpoint:
app.post('/api/add', paintings_controller.add_painting);
For future reading (becase you requested it): I'm not an expert using promises, but it works similarly like the AJAX requests.
When you make a request to the server (GET, POST, PUT, etcetera), you're waiting for a response from this (a collection of data, a message, a succesful/unsuccesful POST/PUT/DELETE, etcetera). Depending of the response, you'll code the expected events (error, success, complete, etcetera).
In this case you're using axios, a new way to do AJAX requests. The equivalent way of the error/success/complete/... events is the then() function. Using this approach you can perform operations that makes new tasks or simply print a response message (in your case) of the server.
From MDN:
The then() method returns a Promise. It takes up to two arguments:
callback functions for the success and failure cases of the Promise.
Let's suppose that we have this snippet of code in AJAX:
$.ajax(
{
url : yourURL,
type : 'POST',
data : yourData,
datatype : 'json',
success : function(data) {
yourSuccessFunction(data);
},
error : function(jqXHR, textStatus, errorThrown) {
yourErrorFunction();
}
});
Using axios, you'll code something like this:
axios.post('/user', {
YourData: yourData
}).then(() => { this.yourSuccessFunction() })
}).catch(() => { this.yourErrorFunction() });
I just found the error. I was making a request to PORT 333 in my axios.post(), but the server was working on port 3333.

How to post raw body using the npm request package

I want to post a request to a service using the npm request package. The service accepts a request body of comma-separated numbers such as 1,2,3, but when I post the request, the body is "1,2,3" instead, which the service does not recognise. I use the following code:
import request from "request";
export function getIt(numbers) {
return new Promise((resolve, reject) => {
const uri = 'http://foo.bar/getIt';
const numbersBody = numbers.join(',')
console.log('post body: ', numbersBody) // prints 1,2,3
request
.post(
uri,
{ json: true, rejectUnauthorized: false, body: numbersBody },
(err, httpResponse, body) => {
let error = err && err.message ? err.message : err;
if (body && body._error_code) {
error = body.message;
}
if (error) {
reject(error);
} else {
resolve(body);
}
}
)
});
When I inspect the network traffic with Wireshark, I can see that the body becomes "1,2,3". It seems to be because the request package writes it as a json object. I have tried to remove the json: true part of the option, and also tried changing it to false, but that throws an exception. So I don't know how to make the string be the raw body, without the quotation marks. Is there any way to make that happen?

How do I use request.js to send text as the request body?

I am attempting to use the request.js library for Node to send a post request with plain text as the body, but I'm finding that the server I'm sending to is receiving an empty body, or perhaps a body consisting of an empty object (logging the body yields {}).
If I send it using Postman, it works properly, so it seems clear that the problem is with my usage of request.js.
The code of the relevant function (with the url changed) is as follows:
function (queryText) {
const options = {
url: "https://myurl.com/",
body: queryText
};
return new Promise ((resolve, reject) => {
request.post(options, (err, response) => {
if (err) reject(err);
else resolve(response);
});
});
}
Anybody know what I'm doing wrong here?
Try adding content-type header like so:
const options = {
url: "https://myurl.com/",
body: queryText,
headers: {
'content-type': 'text/plain'
}
};

Angular Observable not doing the put call

I am working on my first Angular app, but am having a problem going an http.put call. Here is the function I call:
updateUser(columns, values) : Observable<boolean> | boolean {
const headers: Headers = new Headers(); // Need to set content type
headers.append('Content-Type', 'application/json; charset=utf-8');
headers.append('Authorization', `Bearer ${this.authenticationService.token}`);
const options = new RequestOptions({ headers: headers });console.log('test service');
return this.http.put(`${API_URL}users/${this.authenticationService.userId}`, JSON.stringify({ columns: columns, values: values }) , options)
.map((response: Response) => {
console.log('test service1');return Observable.of(true);
})
.catch(e => {
console.log('test service2');return Observable.of(false);
});
When I call the function test service prints to the console, but test service1 and test service2 never print out. I checked my express backend and chrome dev tools and the app is never making the put call to the backend. There are no errors in the console either. So I am missing something, but can't figure it out.
Thank you for any help
Edit: I'm wondering if the issue is because I am just calling this function in another function:
saveColumns(){
this.userService.updateUser('home_columns',this.columns_show);
localStorage.setItem('columns_show', JSON.stringify(this.columns_show) );
}
for http.get functions, I typically do something like this:
loadStudents(page: number, grade = []) {
if (grade.length != 0){
this.student_query_filter = { key:'grade_level',value:grade.join('||') };
} else {
this.student_query_filter = {};
}
this.studentService.getStudentsCount([{ key: 'last_name', value: this.student_search_filter },this.student_query_filter])
.subscribe(
total => this.total = total, //Assign returned student count to local property
err => { console.log(err); });
}
You want to pass the data as an object instead of with JSON.stringify.
You want to return the result from map, not another Observable. If you did want to return a different observable you should change map to switchMap.
The signature should be Observable<boolean> as that is what you are returning.
Be sure to check the developer console in your browser to see if the request is being sent and what the response is. It might be something simple like putting together the URL incorrectly (missing a / for example)
updateUser(columns, values) : Observable<boolean> {
const headers: Headers = new Headers(); // Need to set content type
headers.append('Content-Type', 'application/json; charset=utf-8');
headers.append('Authorization', `Bearer ${this.authenticationService.token}`);
const options = new RequestOptions({ headers: headers });
console.log('test service, sending to: ' + `${API_URL}users/${this.authenticationService.userId}`);
return this.http.put(`${API_URL}users/${this.authenticationService.userId}`, { columns: columns, values: values }, options)
.map((response: Response) => {
console.log('test service1');
return true;
})
.catch(e => {
console.log('test service2');
return false;
});
}
Edit
If your caller is not going to do anything with the result and you do not care what that result is then do not return an Observable at all. Change the return signature to void and execute a subscribe after the call to log the result.
this.http.put(`${API_URL}users/${this.authenticationService.userId}`, { columns: columns, values: values }, options)
.subscribe((response: Response) => {
console.log('test service1'); }
, e => {
console.log('test service2');
});

Categories

Resources