HTTP Client Request for an AWS API Gateway - javascript

I have an angular frontend using typescript and I am trying to make a http request to a AWS API-Gateway. Now the problem is, I need to write the following javascript code as typescript code and send a http request but I do not know how.
The Request to the AWS API gateway needs an AWS Cognito jwtToken (in this case its "accessToken"). I also need to pass the "type", which is the name of the function to be executed on the API (in this case 'POST'). I also need to pass a string which chooses what data I receive.
Auth.currentSession().then(tok => {
const accessToken = tok.getIdToken().getJwtToken();
console.log('from floorview: ' + accessToken);
function requestItem(source) {
$.ajax({
type: 'POST',
url: 'https://XXXXXXXXXX.execute-api.eu-central-1.amazonaws.com/prop/dashboard',
headers: {
Authorization: accessToken
},
data: JSON.stringify({
Source: source.toString(),
tableName: 'h16b-testset',
operation: 'read'
}),
dataType: 'json',
contentType: 'application/json',
success: completeRequest,
error: function ajaxError(jqXHR, textStatus, errorThrown) {
console.error('Error requesting ride: ', textStatus, ', Details: ', errorThrown);
console.error('Response: ', jqXHR.responseText);
alert('An error occured when requesting your unicorn:\n' + jqXHR.responseText);
}
}).then(r => console.log(r));
}
requestItem(996);
function completeRequest(result) {
console.log('Response received from API: ', result);
}
});
}
Now my problem is, how do I write this javascript code as typescript code while using angulars HTTPClient. If there is another method then please tell me. I always get 401s or 403s when I try to run this code using an HTTPClient.
Auth.currentSession().then(tok => {
const accessToken = tok.getAccessToken();
const jwt = accessToken.getJwtToken();
this.authKey = jwt;
const params = new HttpParams().set('Source', '996');
params.append('tableName', 'h16b-testset');
params.append('operation', 'read');
const headers = new HttpHeaders().set('Authorization', this.authKey);
headers.append('content-type', 'application/json');
this.http.request(
'POST',
'https://XXXXXXXX.execute-api.eu-central-1.amazonaws.com/prop/dashboard',
{
headers,
responseType: 'json'
}
).subscribe(
res => {
console.log('hallo' + res);
},
err => {
console.log('error occured with httpclient: ' + err.message);
}
);
});

You can write something like the following (using concatMap operator):
import { from } from 'rxjs';
import { concatMap } from 'rxjs/operators';
export class AuthService {
constructor(private http: HttpClient) {
from(Auth.currentSession())
.pipe(concatMap(tok => this.requestItem(tok, 996)))
.subscribe(
result => console.log('Response received from API: ', result),
err => {
console.log('error occured with httpclient: ' + err.message);
}
);
}
requestItem(token, source) : Observable<any> {
this.http.post(url, {
Source: source.toString(),
tableName: 'h16b-testset',
operation: 'read'
},
headers,
params
);
}
}

Rewrite your http client as:
this.http.post(
'https://XXXXXXXX.execute-api.eu-central-1.amazonaws.com/prop/dashboard',
{
Source: '<id>',
tableName: 'h16b-testset',
operation: 'read'
},
{
headers: new HttpHeaders({'Content-type': 'application/json', 'Authorization': '<token>'})
}
).subscribe(res=> console.log(res), failure => console.error(failure))
This way you will send source in body of request and with authorization token in header.
For more info about HttpClient please see https://angular.io/guide/http.

Related

Body of request not being passed to API

I'm trying to do a PUT request to an update controller from a react form (Mongoose API). Everything is passing over to the request, except the body. Now, this is my first time using FormData, so I'm almost positive that is where the issue lies, but I can't seem to sort out where the problem is..
The Submit action from the form
const clickSubmit = () => {
// console.log('Values on submit before FormData: ', values) // Shows the state object as expected
let userData = new FormData()
values.name && userData.append('name', values.name)
values.email && userData.append('email', values.email)
values.password && userData.append('password', values.password)
values.about && userData.append('about', values.about)
values.photo && userData.append('photo', values.photo)
update({
userId: match.params.userId
}, {
t: jwt.token
}, userData).then((data) => {
if (data && data.error) {
setValues({...values, error: data.error})
} else {
setValues({...values, 'redirectToProfile': true})
}
})
}
The Helper Method that set up the request
const update = async (params, credentials, user) => {
console.log('The params: ', params) // passes the user ID just fine
console.log('The credentials:', credentials) // passes the JWT just fine
console.log('The user object: ', ...user) // has all the information I'm updating, albeit in an array form that I can't really work with
try {
let response = await fetch('/api/users/' + params.userId, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer ' + credentials.t
},
body: user
})
return await response.json()
} catch (err) {
console.log(err)
}
}
And the controller I've commented out the rest of the logic to remove the clutter while I TS this issue
const update = async (req, res) => {
console.log(req)
const user = await User.findById(req.params.userId)
console.log('user after find: ', user) // returns the user that I want to modify from the database
console.log('body of request: ', req.body) // empty object
}
UPDATE:
I was able to get the FormData into an actual object using Object.fromEntries(user) - but it still won't pass into the request.. I have tried two ways:
const update = async (params, credentials, user) => {
console.log('The params: ', params)
console.log('The credentials:', credentials)
console.log('The user object: ', ...user)
let infoToUpdate = Object.fromEntries(user)
console.log('infoToUpdate: ', infoToUpdate);
try {
let response = await fetch('/api/users/' + params.userId, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer ' + credentials.t
},
body: {
"name": infoToUpdate.name,
"email": infoToUpdate.email,
"about": infoToUpdate.about
}
})
return await response.json()
} catch (err) {
console.log(err)
}
}
And
const update = async (params, credentials, user) => {
console.log('The params: ', params)
console.log('The credentials:', credentials)
console.log('The user object: ', ...user)
let infoToUpdate = Object.fromEntries(user)
console.log('infoToUpdate: ', infoToUpdate);
try {
let response = await fetch('/api/users/' + params.userId, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer ' + credentials.t
},
body: infoToUpdate
})
return await response.json()
} catch (err) {
console.log(err)
}
}
But req.body is still an empty object..
This has been solved, and it was all my flippin computer's fault..
On a whim, I killed node_modules and the package.lock files and reinstalled the deps.. and it started working.. My guess is that bodyParser didn't fully install..
Thank you all for the help.

How to resolve Empty error with status code 500 axios?

this is my code :
Express Routes:
router.route('/block')
.post(controller.ticketBlocking);
Express Controller:
const axios = require('axios');
const OAuth = require('oauth-1.0a');
const crypto = require('crypto');
const ticketBlocking = (req, res) => {
const data = JSON.stringify({
source = req.body.source
});
const oauth = OAuth({
consumer: {
key: '....', //Hided the key
secret: '....', //Hided the secret
},
signature_method: 'HMAC-SHA1',
hash_function(base_string, key) {
return crypto.createHmac('sha1', key).update(base_string).digest('base64');
}
});
const request_data = {
url: 'http://link.vvv/blockTicket',
method: 'post',
};
axios({
method: request_data.method,
url: request_data.url,
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
...oauth.oauth.toHeader(oauth.oauth.authorize(request_data)),
},
data : data
})
.then((response) => {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
console.log(error.config);
});
};
the npm package which am using is - "oauth-1.0a"
The problem am facing is, when i use GET method with different end point, i get an output but when ever i use POST method am getting an empty error with status code 500
I dont know where is the mistake, am using oauth1.0a for authorization, please help !

Using request-promise to make an API call using jwt. [ERR_INVALID_ARG_TYPE] received

I'm learning nodejs and trying to make an API call. The API uses JWT to authenticate.
I created these functions to sign a token:
function token() {
const payload = {
iat: Math.floor(new Date() / 1000),
exp: Math.floor(new Date() / 1000) + 30,
sub: "api_key_jwt",
iss: "external",
jti: crypto.randomBytes(6).toString("hex")
};
return new Promise((resolve, reject) => {
jwt.sign(payload, privatekey, { algorithm: "RS256" }, function(
err,
token2
) {
if (err) reject(err);
else resolve(token2);
});
});
}
exports.genToken = async function() {
const header = {
"x-api-key": api
};
const data = {
kid: api,
jwt_token: await token()
};
async function authorization(req, res) {
try {
const auth = await rp({
url: authurl,
method: "POST",
headers: header,
body: data
});
res.send(auth.body);
} catch (error) {
res.send(404).send();
}
}
return {
"x-api-key": api,
Authorization: "Bearer " + authorization()
};
};
This works fine. Then I created a function to make the API call:
const token = require("./index").genToken;
const rp = require("request-promise");
exports.getOrderBook = function(res, error) {
const full_url = url + "order_book";
const auth = token();
rp({
url: full_url,
method: "GET",
headers: auth,
body: {
market: "btceur"
},
json: true
})
.then(function(response) {
res(response);
})
.catch(function(err) {
error(err);
});
};
And I call it using Express:
routes.get("/orderbook", async (req, res, next) => {
try {
const book = await orders.getOrderBook();
res.send(book);
} catch (error) {
next(error);
}
});
However, when I call my API, it shows an error in console:
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of
type string or Buffer. Received type object.
I guess the error is something with the token generation, because if I console.log(auth) in the getOrderBook function, it shows Promise { <pending> }, so probably an object is being passed as the jwt token.
Is it really the problem? I tried a lot of different solutions that I found on internet, however the concept of Async/Await is new to me, and I'm having some troubles to figure it out.
Thanks a lot in advance guys!
Since getToken is an anync function, the return is wrapped in a Promise as well so you would need another anync/await:
exports.getOrderBook = async function() {
let response;
try {
const full_url = url + "order_book";
const auth = await token();
response = await rp({
url: full_url,
method: "GET",
headers: auth,
body: {
market: "btceur"
},
json: true
});
} catch (e) {
// handle error
throw e
// or console.error(e)
}
return response;
};
In this line as well Authorization: "Bearer " + authorization(), authorization is returning a promise
const bearer = await authorization()
return {
"x-api-key": api,
Authorization: "Bearer " + bearer
};
For error handling wrap entire thing in try..catch block
exports.genToken = async function() {
try {
const header = {
"x-api-key": api
};
const data = {
kid: api,
jwt_token: await token()
};
async function authorization(req, res) {
let auth;
try {
auth = await rp({
url: authurl,
method: "POST",
headers: header,
body: data
});
// res object not available
// res.send(auth.body);
} catch (error) {
// res object not available, better throw error and handle in your middleware
// res.send(404).send();
}
return auth
}
const bearer = await authorization()
} catch (e) {
// handle error
}
return {
"x-api-key": api,
Authorization: "Bearer " + bearer
};
}

React and NodeJS: How can i use received data from Server on Client?

I want to use received data from server on client . I use a NodeJS Server with NextJS and React.
I use this function on the server:
function addEmailToMailChimp(email, callback) {
var options = {
method: 'POST',
url: 'https://XXX.api.mailchimp.com/3.0/lists/XXX/members',
headers:
{
'Postman-Token': 'XXX',
'Cache-Control': 'no-cache',
Authorization: 'Basic XXX',
'Content-Type': 'application/json'
},
body: { email_address: email, status: 'subscribed' },
json: true
};
request(options, callback);
}
The function will be run from this point:
server.post('/', (req, res) => {
addEmailToMailChimp(req.body.email, (error, response, body) => {
// This is the callback function which is passed to `addEmailToMailChimp`
try {
var respObj = {}; //Initial response object
if (response.statusCode === 200) {
respObj = { success: `Subscribed using ${req.body.email}!`, message: JSON.parse(response.body) };
} else {
respObj = { error: `Error trying to subscribe ${req.body.email}. Please try again.`, message: JSON.parse(response.body) };
}
res.send(respObj);
} catch (err) {
var respErrorObj = { error: 'There was an error with your request', message: err.message };
res.send(respErrorObj);
}
});
})
The try method is used to verify that an email address could be successfully saved to MailChimp. An appropriate message is sent to the client.
On the Client-Side, i use this function to receive and display the data from the server:
handleSubmit() {
const email = this.state.email;
this.setState({email: ""});
fetch('/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({email:email}),
}).then(res => {
if(res.data.success) {
//If the response from MailChimp is good...
toaster.success('Subscribed!', res.data.success);
this.setState({ email: '' });
} else {
//Handle the bad MailChimp response...
toaster.warning('Unable to subscribe!', res.data.error);
}
}).catch(error => {
//This catch block returns an error if Node API returns an error
toaster.danger('Error. Please try again later.', error.message);
});
}
The problem: The email address is saved successfully at MailChimp, but the message is always displayed: 'Error. Please try again later.'from the .catch area. When i log the error from the catch area i get this:
TypeError: Cannot read property 'success' of undefined
Where is my mistake? I have little experience in Node.js environments. I would be very grateful if you could show me concrete solutions. Thank you for your replies.
With fetch theres no data property on the response. You have to call res.json() and return that promise. From there the response body will be read and deserialized.
handleSubmit() {
const email = this.state.email;
this.setState({email: ""});
fetch('/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({email:email}),
})
.then(res => {
console.log(res); //to make sure the expected object is returned
if(res.data.success) {
//If the response from MailChimp is good...
toaster.success('Subscribed!', res.data.success);
this.setState({ email: '' });
} else {
//Handle the bad MailChimp response...
toaster.warning('Unable to subscribe!', res.data.error);
}
}).catch(error => {
//This catch block returns an error if Node API returns an error
toaster.danger('Error. Please try again later.', error.message);
});
}
Two things you need to change:
Call and wait for res.json() to get the response body as json object.
The result of 1. is your 'data' object that you can use directly
handleSubmit() {
//...
fetch('/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({email:email}),
})
.then(res => res.json())
.then(data => {
if(data.success) {
//...
toaster.success('Subscribed!', data.success);
} else {
toaster.warning('Unable to subscribe!', data.error);
}
}).catch(error => {
//...
});
}

How to upload FormData using Axios?

I am trying to upload 3 photos from frontend using formData. It will call an external API to make the upload. But encountered some errors as below.
Frontend upload
const formData = new FormData()
formData.append('photoA', this.photoA)
formData.append('photoB', this.photoB)
formData.append('photoC', this.photoC)
axios.post(`http://localhost:4172/uploadDocs`,
{
data: formData,
accessToken: store.state.token
},
{ headers: {
// 'Content-Type': 'Application/json',
// 'x-access-token': localStorage.getItem('token')
}
}
).then (function (response) {
return response.data
})
Nodejs upload API
async uploadDocs (req, res) {
const options = {
method: "POST",
url: "https://example.com/api/v1/users/uploadDocuments?access_token=" + req.body.accessToken,
headers: {
//"Authorization": "Basic " + auth,
//"Content-Type": "multipart/form-data"
},
data: req.body.data
};
try {
request(options, function (err,response,body){
if (err) {
res.send(err)
} else {
res.send(response.body)
}
})
} catch (error) {
res.status(400).send({
error: "Server error."
})
}
}
So there are 2 errors here:
a) Frontend error: It keeps giving Cannot POST / error in html
b) Backend error:
<h1>Cannot read property 'photoA' of undefined</h1>
<h2></h2>
<pre></pre>
Been struggling with this for days. Any help will be very much appreciated.

Categories