Creating an Asana Task using a POST http request - javascript

I'm trying to use the asana-api to create a Task using a POST http request but I keep getting a 400 bad request as a response.
I managed to get data from the Asana-api using ( a GET request ), but I'm having trouble sending data to Asana with ( a POST request )
I'm using the 'request' module to do the api call
here's the error message :
`{"errors":[{
"message":"Could not parse request data,invalid JSON",
"help":"For more information on API status codes and how to handle them,
read the docs on errors: https://asana.com/developers/documentation/getting-started/errors"}
]}`
Here's my code:
testTask(){
var taskName = "Test Name for a Test Task"
var workspaceID = "123456789"
var projectID = "123456789"
var assigneeID = "123456789"
var parentID = null
this.createTask(taskName, workspaceID, projectID, assigneeID, parentID)
}
createTask(taskName, workspaceID, projectID, assigneeID, parentID){
var token = "0/1234abcd5678efgh9102ijk"
var bearerToken = "Bearer " + token
var task = {
data: {
assignee: "me",
notes: "test test test test",
workspace: workspaceID,
name: taskName,
projects: [projectID],
parent: parentID
}
}
var options = {
"method" : "POST",
"headers" : {"Authorization": bearerToken},
"contentType": "application/json",
"payload" : JSON.stringify(task)
}
try {
var url = "https://app.asana.com/api/1.0/tasks";
request.post(url, options, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
}
catch (e) {
console.log(e);
}
}
I also tried a different implementation :
createTask(){
var token = "0/1234abcd5678efgh9102ijk"
var bearerToken = "Bearer " + token
var options = {
"method" : "POST",
"headers" : {"Authorization": bearerToken},
}
try {
request.post("https://app.asana.com/api/1.0/tasks?workspace=1234567&projects=765534432&parent=null&name=taskName&assignee=me", options, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
}
catch (e) {
console.log(e);
}
}

Based on the examples provided by the request module, it appears that your options object uses payload as a key, but it should be body.

Related

Why my NULL check is always failing in Node.js?

I am developing a REST API with AWS Lambda, API Gateway, and Node.js.
Here is my code:
const mysql = require('mysql2');
const PropertiesReader = require('properties-reader');
const prop = PropertiesReader('properties.properties');
const con = mysql.createConnection({
host : prop.get('server.host'),
user : prop.get("server.username"),
password : prop.get("server.password"),
port : prop.get("server.port"),
database : prop.get("server.dbname")
});
exports.getMilestoneStatusByID = (event, context, callback) => {
const { id } = event.queryStringParameters;
if(id==null)
{
var response = {
"statusCode": 404,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify("Missing Parameters"),
"isBase64Encoded": false
};
callback(null, response)
}
else{
console.log("id", id);
// allows for using callbacks as finish/error-handlers
context.callbackWaitsForEmptyEventLoop = false;
const sql = "select * from milestone_status where idmilestone_status = ?";
con.execute(sql, [id], function (err, result) {
if (err) throw err;
var response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify(result),
"isBase64Encoded": false
};
callback(null, response)
});
}
};
In my code I am accepting a parameter called id, then get data from the database and return back as the response. If the id is not provided, i am sending an error response.
But, in any case the id is null or no parameter provided, then the user gets the standard AWS error output, "message": "Internal server error". In console, th But what I need is to pass 404 status code, with the message Missing Parameters.
e below error get printed.
Lambda returned empty body!
Invalid lambda response received: Invalid API Gateway Response Keys: {'trace', 'errorMessage', 'errorType'} in {'errorType': 'TypeError', 'errorMessage': "Cannot destructure property 'id' of 'event.queryStringParameters' as it is null.", 'trace': ["TypeError: Cannot destructure property 'id' of 'event.queryStringParameters' as it is null.", ' at Runtime.exports.getMilestoneStatusByID [as handler] (/var/task/source/milestone-status/milestonestatus-getbyid.js:17:11)', ' at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)']}
How can I implement null check and send the error that I am looking for?
The error says that event.queryStringParameters is undefined, not the .id in it. You can extend your check to also check for event.queryStringParameters, although you should check the documentation if that's even normal:
exports.getMilestoneStatusByID = (event, context, callback) => {
const params = event.queryStringParameters;
if (!params || params.id == null) {
var response = {
"statusCode": 404,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify("Missing Parameters"),
"isBase64Encoded": false
};
callback(null, response)
} else {
const { id } = params;
// ...
}

Node.js : How to do error handing in AWS Lambda?

I am developing a REST API with AWS Lambda, API Gateway. Language is Node.js.
Please check the below code. There I am accepting a parameter called id then get data from the database and return back as the response.
const mysql = require('mysql2');
const PropertiesReader = require('properties-reader');
const prop = PropertiesReader('properties.properties');
const con = mysql.createConnection({
host : prop.get('server.host'),
user : prop.get("server.username"),
password : prop.get("server.password"),
port : prop.get("server.port"),
database : prop.get("server.dbname")
});
exports.getMilestoneStatusByID = (event, context, callback) => {
const { id } = event.queryStringParameters;
console.log("id", id);
// allows for using callbacks as finish/error-handlers
context.callbackWaitsForEmptyEventLoop = false;
const sql = "select * from milestone_status where idmilestone_status = ?";
con.execute(sql, [id], function (err, result) {
if (err) throw err;
var response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify(result),
"isBase64Encoded": false
};
callback(null, response)
});
};
However, in any case the id is null or no parameter provided, then the user gets the standard AWS error output, "message": "Internal server error". But what I need is to pass 404 status code, with the message Missing Parameters.
I tried to put the whole block inside the handler into a try-catch and tried to fire the following code inside the catch
var response = {
"statusCode": 404,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify("Missing Parameters"),
"isBase64Encoded": false
};
callback(null, response)
But non of these stopped me from getting the standard AWS error message, "message": "Internal server error".
How can I implement the error that I am looking for?
I am answering my own question. The issue was not with the returning of the error, but with the null check. This worked.
exports.getMilestoneStatusByID = (event, context, callback) => {
const params = event.queryStringParameters;
if (!params || params.id == null) {
var response = {
"statusCode": 404,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify({ error: "Missing Parameters" }),
"isBase64Encoded": false
};
callback(null, response)
} else {
const { id } = params;
// ...
}

how to get the response api with status code is 400?

I consume api and when the api returns 200 status code, I return the response, but when the api returns 400 status code the api returns array with the errors, my questions is how can i get this array errors and return this array.
the code
try {
const config = {
method: 'get',
url: 'http://localhost:4000/api/orders',
headers: {'Key': '96db259b-2239-4abb-9b9d-a682a1de6b3c'}
}
const result = await axios(config)
return result.data
} catch (error) {
console.log('error ' + error)
returns result.data.errors
}
this the response whit the status code is 400.
"errors": [
{
"value": "96db259b-2239-4abb-9b9d-a682ssa1de6b3c",
"msg": "the API key 96db259b-2239-4abb-9b9d-a682ssa1de6b3c is invalid",
"param": "key",
"location": "headers"
}
]
You can do like this
try {
const config = {
method: 'get',
url: 'http://localhost:4000/api/orders',
headers: {'Key': '96db259b-2239-4abb-9b9d-a682a1de6b3c'}
}
const result = await axios(config)
if(result.status != 200) {
throw new Error(`[Status ${result.status}] Something went wrong `);
}
return result.data
} catch (error) {
console.log('error ' + error)
returns error.message;
}
Only do you need call the message attribute of error, for example:
try {
const config = {
method: 'get',
url: 'http://localhost:4000/api/orders',
headers: {'Key': '96db259b-2239-4abb-9b9d-a682a1de6b3c'}
}
const result = await axios(config)
return result.data // this only called with success response, status code 200
} catch (error) {
console.log('error ' + error)
returns error.message;
}

Create new product by calliing shopify api

I am trying to create a new product by calling the shopify product api (/admin/api/2020-01/products.json). I am trying to achieve this using the "https" module. Below is the sample code
const url1 = 'https://{api_token}#tuscstore.myshopify.com/admin/api/2020-01/products.json';
var obj = {
"product":[
{
"title": "Saturn",
"body_html": "<p>The epitome of elegance</p>",
"vendor": "Soltions inc",
"product_type": "Planets",
"handle": "saturn",
"tags": "",
"images": [
{
"src": "https://solarsystem.nasa.gov/system/stellar_items/image_files/38_saturn_1600x900.jpg"
}
]
}
]
};
const https = require('https');
var data = JSON.stringify(obj)
const options = new URL(url1);
var req = https.request(options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
/* res.on('data', (d) => {
process.stdout.write(d);
}); */
});
req.on('error', (e) => {
console.error(e);
});
req.write(data);
req.end();
const Index = () => (
<div>
<p>Sample app using React and Next.js</p>
</div>
);
export default Index;
I am facing 2 problems,
when I do "process.stdout.write(d)", I receive cannot readproperty "write" undefined.
If I comment it out as I have done in
the code above, I don't get the error.
In either case I get the statuscode as 200, and not 201 which is what I shoudl receive according to shopify's docs.
Can someone please help me with what is going wrong?
Edit: Using Post,I get a type error
const https = require('https');
var data = JSON.stringify(obj)
var options = {
hostname: 'https://{apikey:password}#tuscstore.myshopify.com/admin/api/2020-01',
path: '/products.json',
method: 'POST',
headers: {
'Content-Type': 'application/json',
/*'Content-Length': data.length*/
'Authorization' : 'API_TOKEN'
}
};
var req = https.request(options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
});
req.on('error', (e) => {
console.error(e);
});
req.write(data);
req.end();
TypeError: Failed to execute 'fetch' on 'Window': Failed to parse URL from https://[https://{APIKEY:PWD}#tuscstore.myshopify.com/admin/api/2020-01]/products.json
you creating a new product you have to make http POST request , and now your making http GET request you should update your options like so :
const options = {
hostname: 'https://apikey:password#<#store_url>/admin/api/2020-01', // your host name
path: '/shop.json', // your end point
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization' : 'YOUR_API_TOKEN'
}
}
OR you can use this package to solve all your problems https://www.npmjs.com/package/shopify-api-node

How do I format a request.get using an XMLHttpRequest example

Goal
I would like to use the npm package request to get data from an API endpoint. The example I am following uses XMLHttpRequest() to get the data.
Question
How do I convert the XMLHttpRequest() to a request.get
Example Code
The OnSIP example I am following provides the following:
cURL example:
curl -X POST \
--data \
'Action=SessionCreate&Username=john.doe%40example.onsip.com&Password=mysuperpassword' \
https://api.onsip.com/api
XMLHttpRequest() example:
var data = new FormData();
data.append('Action', 'SessionCreate');
data.append('Username', 'john.doe#example.onsip.com');
data.append('Password', 'mysuperpassword');
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.onsip.com/api', true);
xhr.onload = function () {
console.log(this.responseText);
}
xhr.send(data);
What I Tried
cURL
When I put my credentials into the cURL command, I have success, and the response indicates <IsValid>true</IsValid>
.
node.js
I took the cURL example and used this cURL to Node.js tool to get started.
// Config Settings
const onsipAction = "SessionCreate";
const onsipEmail = encodeURIComponent(onsipConfig.email);
const onsipPassword = onsipConfig.password;
const dataString = "Action=" + onsipAction +
"&Username=" + onsipEmail +
"&Password=" + onsipPassword;
console.log("dataString :", dataString);
const onsipSessionCreateOptions = {
url: "https://api.onsip.com/api",
method: "POST",
body: dataString
};
exports.getOnsipSessionId = function (request){
return (new Promise((resolve, reject) => {
request.get(onsipSessionCreateOptions, function (err, _resp, body) {
if (err) reject(err);
else {
console.log("body :", body);
resolve(body);
}
});
}).catch(err => console.log("err:", err)));
};
Logs
I see this error in the body, but not sure what it means.
Accessor parameter is required, but none was specified.
datastring: Action=SessionCreate&Username=fakename%40jahnelgroup.onsip.com&Password=fakepass
and this is the body:
<?xml version="1.0" encoding="UTF-8"?>
<Response
xmlns="http://www.jnctn.net/ns/rest/2006-01">
<Context>
<Action>
<IsCompleted>false</IsCompleted>
</Action>
<Request>
<IsValid>false</IsValid>
<DateTime>2019-02-06T15:18:10+00:00</DateTime>
<Duration>1</Duration>
<Errors>
<Error>
<Parameter>Action</Parameter>
<Code>Accessor.Required</Code>
<Message>Accessor parameter is required, but none was specified.</Message>
</Error>
</Errors>
</Request>
<Session>
<IsEstablished>false</IsEstablished>
</Session>
</Context>
</Response>
The Issue
As Mo A shows in his answer, I missed two things:
request.get is wrong, instead request.post is correct.
The OnSIP endpoint is ready for formData
The code that works for me
// Config Settings
const onsipAction = "SessionCreate";
const onsipEmail = onsipConfig.email;
const onsipPassword = onsipConfig.password;
const options = { method: "POST",
url: "https://api.onsip.com/api",
headers:
{ "content-type": "multipart/form-data;" },
formData:
{ Action: onsipAction,
Username: onsipEmail,
Password: onsipPassword,
Output: "json"
}
};
exports.getOnsipSessionId = function (request){
return (new Promise((resolve, reject) => {
request.post(options, function (err, response, body) {
if (err) reject(err);
else {
console.log("body :", body);
resolve(body); // Contains SessionId
}
});
}).catch(err => console.log("err:", err)));
};
Thanks, Mo A, OnSIP Devs, and MShirk for the support!
Your request appears to be a POST, rather than a GET.
Try the following snippet to recreate your XMLHttpRequest using Node:
var request = require("request");
var options = { method: 'POST',
url: 'https://api.onsip.com/api',
headers:
{ 'content-type': 'multipart/form-data;' },
formData:
{ Action: 'SessionCreate',
Username: 'john.doe#example.onsip.com',
Password: 'mysuperpassword' } };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
It's basic (doesn't include email encoding for instance), but should in theory work.

Categories

Resources