Dynamic Url on Axios Get Express - node.js

I tried to hit third party API with Axios express js
here's my code
controller.js
let randNumb = '129383'
let response = await api.get(randNumb)
console.log(response)
api.js
const axios = require('axios').default;
let API = {}
api.get = (randNumb) =>{
const url= process.env.Host+randNumb+'/result'
var config = {
method: 'get',
url: url,
headers: {
'Accept': '*/*'
}
};
await axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
return JSON.stringify(response.data)
})
.catch(function (error) {
console.log(error);
});
}
But I keep getting status 412 For hit that API but when I hardcoded that URL like :
let url= https://thridParty.com/129383/result on api.js it getting worked.
I need to custom or dynamic this URL
could you guys help me?

// Does not work
const url = process.env.Host + randNumb + '/result'
// Does work
const url = 'https://thridParty.com/129383/result'
If this is like you said, then maybe the concatenated string does not result in a valid url.
Please check the value of the url variable, it will probably not look like the hard coded url, might miss a slash or something else.

Related

Nodejs + Axios Post returns undefined value

I am using React + NodeJS & Axios but have been trying to send a post request but experiencing difficulties.
The request seems to be posting successfully, but all actions at the nodejs server is returning in the "undefined" data value, even if the data is passed successfully shown in the console.
REACT
const fireAction = (data1, data2) => {
const data = JSON.stringify({data1, data2})
const url = `http://localhost:5000/data/corr/fire`;
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'AUTHCODE',
}
}
axios.post(url, data, config)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
fireAction("Oklahoma", "Small apartment")
NODE
app.post('/data/corr/fire', async (req, res) => {
try {
const data = req.body.data1;
console.log(data)
} catch(e) {
res.send({success: "none", error: e.message})
}
});
Result of node: "undefined"
I have added the following body parser:
app.use(express.json());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
I am not sure why this error is happening. I see there is similar questions to mine: however none of them are applicable as I'm using both express and body parser which is already suggested.
You're POSTing JSON with a content-type meant for forms. There's no need to manually set content-type if you're sending JSON, but if you want to manually override it, you can use 'Content-Type': 'application/json', and access the response in your route with req.body. If it does need to be formencoded, you'll need to build the form:
const params = new URLSearchParams();
params.append('data1', data1);
params.append('data2', data2);
axios.post(url, params, config);

PUT request works in Postman but not a deno typescript file as a fetch request

I can do a put request just fine in Postman.
But when I try to do the same put request in a deno fresh app through a fetch command like this:
async function sendSignature() {
const signer = provider.getSigner();
const nonce = "asdf123492fd";
const signatureSigned = await signer.signMessage(nonce);
const headers = new Headers({
'Content-Type': 'application/json'
});
const opts = {
method: 'PUT',
headers: headers,
body: JSON.stringify({
key: props.singleUser,
wallet_address: walletAddrs,
signature: signatureSigned
})
}
console.log(opts.body);
const rawPosts = await fetch('http://localhost:4000/users/kythis1', opts);
console.log(rawPosts);
}
Btw all of the values are being populated in body. I can confirm that key, wallet_address, and signature are not null and are strings. It fails though... Here's what the browser's console looks like.
This is the entry point for the backend oak (deno's version of express) server.
import { Application } from "https://deno.land/x/oak/mod.ts";
import { APP_HOST, APP_PORT } from "./config.js";
import router from "./routes.js";
import _404 from "./controllers/404.js";
import errorHandler from "./controllers/errorHandler.js";
import { oakCors } from "https://deno.land/x/cors/mod.ts";
const app = new Application();
app.use(oakCors()); // Enable CORS for All Routes
app.use(errorHandler);
app.use(router.routes());
app.use(router.allowedMethods());
app.use(_404);
console.log(`Listening on port:${APP_PORT}...`);
await app.listen(`${APP_HOST}:${APP_PORT}`);
This is the function that is getting called by the put request:
import User from "../db/database.js";
export default async ({ request, response }) => {
if (!request.hasBody) {
response.status = 400;
response.body = { msg: "Invalid user data" };
return;
}
const body = request.body();
const {
key, wallet_address, signature
} = JSON.parse(await body.value);
console.log(signature);
if (!key) {
response.status = 422;
response.body = { msg: "Incorrect user data. Email and key are required" };
return;
}
const foundUser = await User.where('key', '=', key).first();
if (!foundUser) {
response.status = 404;
response.body = { msg: `User with key ${key} not found` };
return;
}
foundUser.wallet_address = wallet_address;
foundUser.updated_at = new Date();
const updatedResp = await foundUser.update();
response.body = { msg: "User updated", updatedResp };
};
Finally this is the backend routes:
import { Router } from "https://deno.land/x/oak/mod.ts";
import getUsers from "./controllers/getUsers.js";
import getUserDetails from "./controllers/getUserDetails.js";
import createUser from "./controllers/createUser.js";
import updateUser from "./controllers/updateUser.js";
//import deleteUser from "./controllers/deleteUser.js";
const router = new Router();
router
.get("/users", getUsers)
.get("/users/:key", getUserDetails)
.post("/users", createUser)
.put("/users/:key", updateUser);
//.delete("/users/:id", deleteUser);
export default router;
So why can I successfully call this function with a Postman put request, but I can't do a successful put request with fetch through a typescript file?
Your postman and fetch call aren't exactly the same.
Looking at postman it has 8 headers, and content-type seems to be set on Text.
While the fetch() is set on application/json.
When content type is application/json your request.body() is likely already parsed. Thus another JSON.parse will throw an error.
One easy fix with your current code would be to set your javascript headers to this:
const headers = new Headers({
'Content-Type': 'text/plain'
});
This will avoid 2 times parsing of the json file.
But the better fix would be to actually use application/json and see/log what request.body() returns.
Postman simply doesn’t care about CORS headers. So CORS is just a browser concept and not a strong security mechanism. It allows you to restrict which other web apps may use your backend resources.
You have to just specifies CORS (Access-Control-Allow-Origin) headers.

Not able to pass JSON data using FETCH

I am having an API Service build on node js running on port 3001 and a web UI using REACT & running on port 3000. I have to POST details from Web page to the API in JSON Format. I am able to hit the API, however I could not get the JSON on the API. Its being received as {}. However the API is working fine from postman.
Could some one please share light on where i am missing.
Source code of API
const util = require('util')
const request = require("request");
const express = require('express')
const app = express();
const port = 3001
app.use(express.json());
app.use(express.urlencoded( {extended: false}));
const bodyParser = require('body-parser');
const { json } = require('express/lib/response');
app.post('/PostPatronDetailsone',(req,res) => {
async function run() {
try {
console.log('Request received from REACT ONE');
// parse application/json
app.use(bodyParser.json())
console.log(req.body);
// Respond back
res.send('Transaction Sent');
} finally {
// Ensures that the client will close when you finish/error
}
}
run().catch(console.dir);
});
app.listen(port, () => console.log('Server is listening at port ' + port));
Code Snippet of Web making the HTTP POST
import React from 'react';
class Signup extends React.Component {
constructor(props) {
super(props);
this.state = {
postId: null
};
}
async componentDidMount() {
// Simple POST request with a JSON body using fetch
let payload = {'first_name': 'TEST' };
var data = new FormData();
data.append( "json", JSON.stringify( payload ) );
const requestOptions = {
method: 'POST',
mode: 'no-cors',
headers: { 'Content-Type': 'application/json','Accept':'application/json' },
body: data,
redirect: 'follow'
};
var response = await fetch('http://localhost:3001/PostPatronDetailsone', requestOptions);
var data1 = await response.json();
var data2 = data1.text();
alert(data2);
//this.setState({ postId: data1.insertedid });
}
render() {
const { postId } = this.state;
return (
<div className="card text-center m-3">
<h5 className="card-header">Simple POST Request</h5>
</div>
);
}
}
export default Signup;
Console Output of API Service
Server is listening at port 3001
Request received from REACT ONE
{}
Request received from REACT ONE
{}
It is because you send formData, instead stringify the object and send it to body like this:
async componentDidMount() {
// Simple POST request with a JSON body using fetch
let payload = {first_name: 'TEST' };
const requestOptions = {
method: 'POST',
mode: 'no-cors',
headers: { 'Content-Type': 'application/json','Accept':'application/json' },
body: JSON.stringify(payload ),
redirect: 'follow'
};
var response = await fetch('http://localhost:3001/PostPatronDetailsone', requestOptions);
var data1 = await response.json();
var data2 = data1.text();
alert(data2);
//this.setState({ postId: data1.insertedid });
}
Please change the code as follows:
let payload = {'first_name': 'TEST' };
fetch('http://localhost:3001/PostPatronDetailsone',{
body:JSON.stringify(payload),
method:'post',
mode: 'no-cors',
headers: {
"Content-Type": "application/json"
},
}).then((res)=>res.json()).then((data)=>console.log(data));
And from controller in backend remove that line as you are already using express.json() which is equivalent to that line:
app.use(bodyParser.json()) // remove it
You have 3 key problems here:
You are posting a FormData object (which gets converted to a multipart/form-data encoding) and not JSON
You are setting no-cors mode which causes the browser to silently discard any instructions to do anything that would require CORS permission (such as setting the application/json content-type or reading the response)
There won't be a text() method on anything parsed from JSON
const data = {'first_name': 'TEST' };
const payload = JSON.stringify(data)
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json','Accept':'application/json' },
body: payload,
redirect: 'follow'
};
const response = await fetch('http://localhost:3001/PostPatronDetailsone', requestOptions);
const parsed_json = await response.json();
console.log(parsed_json);
You will also need to change the server-side code to grant permission to the JavaScript to read the response and send the JSON formatted request. Use the cors module for that.
app.use(cors());
Also note that body parsing middleware needs to be set up when the application starts and not in the middle of a route. The body-parser module has been obsoleted as Express has its features built-in now.
The following is good:
app.use(express.json());
The following is bad:
const bodyParser = require('body-parser');
and
app.use(bodyParser.json())
Your route code doesn't need to be any more complex than:
app.post('/PostPatronDetailsone', async (req,res) => {
console.log('Request received from REACT ONE');
console.log(req.body);
res.json('Transaction Sent');
});
Note that since you are trying to parse the response as JSON in the client side code, I've had to change send to json so that the server outputs JSON instead of plain text.

AWS-Lambda 302 Not Redirecting after getting response from Axios (Frontend)

I'm trying to setup a Google-OAuth flow using serverless and AWS-Lambdas. To start, I have a button that kicks off the process by hitting a lambda endpoint. However, the page never actually redirects to the authentication page. Instead I get an error on the FE:
Request failed with status code 302
Frontend logic:
const redirectToGoogleOAuth = async (user) => {
try {
const endpoint = process.env.GOOGLE_PATH_ENDPOINT;
const response = await axios.get(endpoint, {
responseType: 'text',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${user}`,
},
});
// Expect redirect at this point
return response.data.data;
} catch (err) {
throw new Error(err.message);
}
};
Lambda Endpoint:
module.exports = async (event, context) => {
const responseType = 'code'
const googleAuthorizeURL = 'https://accounts.google.com/o/oauth2/v2/auth'
const scope = 'openid email https://www.googleapis.com/auth/contacts.readonly'
const accessType = 'offline'
try {
const params = [
`response_type=${responseType}`,
`client_id=${googleClientId}`,
`redirect_uri=${baseURL}`,
`scope=${scope}`,
`state="state"`,
`access_type=${accessType}`
]
const googleOAuthEndPath = `${googleAuthorizeURL}?${params.join('&')}`
const response = {
statusCode: 302,
body: '',
headers: {
location: googleOAuthEndPath
}
}
return response
} catch (err) {
return response(400, err.message)
}
}
In the lambda-response, I've added a header for location with the google-path. However, the frontend does not seem to consume the response correctly. The frontend interprets the 302 as in error instead of redirecting to the specific page. Any ideas on how I may resolve this so it actually redirects?
Axios uses XHR, which always follows redirects by itself and therefore Axios can't do anything about it (unless you rely on hacks, discussed in the same link).
You might have to use something other than Axios for this part, such as the Fetch API, which supports manual redirects.
GitHub user parties suggested the fetch() equivalent in the same Axios issue linked above:
fetch("/api/user", {
redirect: "manual"
}).then((res) => {
if (res.type === "opaqueredirect") {
window.location.href = res.url;
} else {
return res;
}
}).catch(handleFetchError);

Axios with react native not returning document and crashes app

Edit
Ok, so my method was just fine. For some reason, when I changed const response = await... to const res = await.. (or any other name besides "response" for that matter), it worked.. If this isn't a memory leak, then I have no idea what the heck this could have been. If anyone has any insight, I'd appreciate it.
I am making a request from my client:
const config = { headers: { "Content-Type": "application/json" } };
const data = JSON.stringify({ postId });
console.log('sending request'); // prints
const response = await axios.post(
`http://${GATEWAY}:5000/api/posts/single`,
data,
config
);
console.log("response received"); // never reached
But request received is never printed.
My backend route has this,
const post = await Post.findById(postId).populate("likes");
console.log(post); // prints post
return res.json(post);
And it appropriately find the post and logs it to the console. I'm not sure what's going on. No errors are printed anywhere and the app crashes after some time. It's probably waiting for the response.
Also, when I do
return res.json(null)
my client receives the response. But when I try to return the post or even if I try to
return res.json( { msg: "Hello World" } );
it hangs.
In addition, I do similar axios requests throughout the app -- they work and behave as expected. Not sure what I'm doing wrong here.
I've even tried,
const response = await axios.get(
`http://${GATEWAY}:5000/api/posts/${postId}`,
);
But it behaves and fails in the same way. If I let the request hang for too long, the app just gives up and crashes.
Note, also, I'm using axios instead of axios-react-native
Are you sure it is "http" not "https"
or
else try:
const url = `${apiBaseUrl}/someUrlText/someUrlText/`;
const headers = {headers: { "Content-Type": "application/json"}};
const body = JSON.stringify({ postId });
axios
.post(url, body, headers)
.then(res => {
console.log("request received",res);
})
.catch(err => console.log("TODO: Handle error axios", err));

Resources