Getting an empty array on Axios GET request - node.js

I'm trying to do a GET request using Axios. The API's response includes several objects that are properly populated. However, one particular object/field is an array that always shows up as an empty array.
Here's the response I get (note the "users" object with the empty array):
{
url: 'https:/<removed>/customers/<removed>/users?number=41442268000',
users: [],
customer: {
url: 'https://<removed>/customers/<removed>',
id: '<removed>',
name: 'CX Customer1'
},
paging: { offset: 0, limit: 2000, count: 0 }
}
The strange thing is that it works perfectly fine when I use Postman to query the exact same resource:
{
"url": "https://<removed>/customers/<removed>/users?number=8013334001",
"users": [
{
"url": "https://<removed>/customers/<removed>/users/<removed>",
"id": "b1703d6a<removed>",
"bwId": "<removed>.webex.com",
"lastName": "One",
"firstName": "Gus1",
"displayName": "Gus1 One",
"type": "USER",
"callerIdLastName": "One",
"callerIdFirstName": "Gus1",
"callerIdNumber": "+1-8013334001",
"numbers": [
{
"external": "+1-8013334001",
"extension": "4001",
"primary": true
}
],
"location": {
"name": "Salt Lake City",
"id": "9a03e3e<removed>",
"url": "https://<removed>/customers/<removed>/locations/<removed>"
}
}
],
"customer": {
"url": "https://<removed>/customers/<removed>",
"id": "4c1ccbe<removed>",
"name": "CX Customer1"
},
"paging": {
"offset": 0,
"limit": 2000,
"count": 1
}
}
As observed in the above Postman response, the "users" array has an object inside of it.
Here's my Node.js code:
function getUsersByTN(customerInfo, userData) {
let rowNumber = 1;
let successCount = 0;
let failureCount = 0;
axios.defaults.headers.common["Authorization"] = `Bearer ${customerInfo.token}`;
console.log('Attempting to find users on Webex Calling using their phone number...');
return new Promise(async (resolve, reject) => {
try {
for (let data of userData) {
rowNumber++;
const phoneNumber = data.TN;
const getUserURL = `https://<removed>/customers/` +
`${customerInfo.customerId}/` +
`users?number=` +
`${phoneNumber}`;
const result = await axios.get(getUserURL);
console.log(result.data);
resolve(result);
}
}
catch (err) {
reject(new Error(err));
}
})
}
I have also tried to replace the async/await format with the more traditional way of using promises, but got the same result:
axios.get(getUserURL)
.then(result => console.log(result.data))
.catch(err => console.log(err));
What am I missing?
Thanks!
-Gus

I found the problem. My input CSV file had users with phone numbers that did not exist. As soon as I updated it with valid/existing phone numbers, it worked as expected.
The thing that threw me off is that the API still replies with a "200 OK" when I provide invalid phone numbers. I was expecting a "404 not found" for invalid numbers, so I didn't even think about checking the numbers.
My first thought was that this was a bug on the API. In other words, I initially thought that the API should reply with a "404 not found". However, as I thought more about this, I realized that a "200 OK" with an empty result is a more appropriate response. That's because a "404" would incorrectly indicate that the API resource could not be found, which would imply that the request was sent to an invalid URL. That's clearly not what we want. Instead, we want to let the application know that it reached a valid API resource, but that no results were found for the provided searched criteria.

Related

ValidationException: The provided starting key is invalid - What to put in ExclusiveStartKey - dynamodb

I am working with nodeJS, dynamo db and AWS API gateway, where I am new to dynamo db,
The requirement is of converting the response into pages, using pagination in my code,
so that from each API call, we got some pagination token and that can be passed from the UI, to get another set of response.
For that I have got the LastEvaluatedKey in object format, given below:
{
"userName": {
"S": "username"
},
"Id": {
"S": "id-value"
}
}
What I found is I need to set ExclusiveStartKey in following format:
ExclusiveStartKey = {
"ID": {"S": LastEvaluatedKey}
};
On doing this, I am getting following error : ValidationException: The provided starting key is invalid.
Can someone please suggest, where I am going wrong, or what needs to be passed in ExclusiveStartKey value?
after edit:
added code :
my function:
var response = await dynamo.query(params).promise();
if(response['Items'].length > 0) {
addDataApps = [...addDataApps, ...response['Items']];
}
if (response.LastEvaluatedKey) {
result = {
addAppData: addDataApps,
paginationToken: response.LastEvaluatedKey
};
return result;
} else {
result = {
addAppData: addDataApps,
paginationToken: null
};
return(result);
}
and following is the response from postman
{
"data": [
{
"data":"data value"
},
{
"data":"data value"
}
],
"paginationToken": {
"userName": {
"S": "username"
},
"id": {
"S": "id"
}
}
}
then I am doing this to assign it to startKey:
params.ExclusiveStartKey = {
"ID": {"S": {
"userName": {
"S": "username"
},
"id": {
"S": "id"
}
}}
};
solution:
Its solved now, as I am new to dynamodb, I was not aware about the pagination working, somehow I found that the token I was passing was into string format, that was not accepted as a exclusiveStartKey, so I have converted the format into object adding the partition key and sort key of the table.
Thanks in advance.
You'd probably benefit from this GitHub project that hosts a lot of sample code. Here are two Node.js examples showing pagination.
https://github.com/aws-samples/aws-dynamodb-examples/blob/master/DynamoDB-SDK-Examples/node.js/WorkingWithQueries/query-with-pagination-all-data.js
https://github.com/aws-samples/aws-dynamodb-examples/blob/master/DynamoDB-SDK-Examples/node.js/WorkingWithScans/scan-fetch-all-pagination.js

getting error response for the Update api

I am new to this swagger and i created a small demo project in node-js to see how swagger will really works. I created 5 api's which 4 are working perfectly and when it comes to PUT api I am getting error ,but when i tried in postman it is working. Please look at the code below.
export let updateUser = async(req: Request, resp: Response) => {
try{
const use = await User.findById(req.params.id);
use.name = req.body.name;
// use.email = req.body.email;
const a1 = await use.save();
resp.json("successfully updated");
} catch(err) {
resp.send('Error')
}
}
this is the api which is calling above method in app.ts
//put-request
app.put('/user/update/:id',controller.updateUser);
This is the the swagger json of put API
"/user/update/{id}": {
"put": {
"tags": [
"Update-Api"
],
"summary": "Update-user",
"description": "To updatre the particular user",
"operationId": "updateUser",
"consumes": ["application/json"],
"parameters":[
{
"name":"Id",
"in":"path",
"description":"enter the id of the user",
"required":true,
"type":"string"
},
{
"name":"body",
"in":"body",
"description":"Enter the update value",
"required":true,
"$schema": {
"type": "#/definations/User"
}
}
],
"responses": {
"400": {
"description": "Invalid user supplied"
},
"404": {
"description": "User not found"
}
}
}
}
If you paste your API definition into https://editor.swagger.io, it will flag 2 syntax errors in the PUT operation. Make sure to fix these errors before testing your API.
In the parameter definition, change "name":"Id" to "name":"id" (lowercase id) to match the parameter letter case in the path template.
In the body parameter, change $schema to schema.

elasticsearch node.js API remove an object from an array on a document using painless script results in array Index Out of Bounds

I want to remove items (an object) from an array on a document in elasticsearch, however whenever I try and run my update script using painless, I receive an Array Index Out of Bounds exception.
I'm using the javascript elasticsearch npm package to search elasticsearch for the relevant documents which then returns me data like:
"_index": "centres",
"_type": "doc",
"_id": "51bc77d1-b514-4f4e-85fa-412def6829f5",
"_score": 1,
"_source": {
"id": "cbaa7daa-f1a2-4ac3-8d7c-fc981245d21c",
"name": "Five House",
"openDays": [
{
"title": "new open Day",
"endDate": "2022-03-22T00:00:00.000Z",
"id": "82be934b-eeb1-419c-96ed-a58808b30df7"
},
{
"title": "last open Day",
"endDate": "2020-12-24T00:00:00.000Z",
"id": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
}
]
}
I then want to go through and remove certain items from the openDays array. I've created an array of the items I want to remove, so for the above example:
[
{
id: '51bc77d1-b514-4f4e-85fa-412def6829f5',
indexes: [
{
"title": "last open Day",
"endDate": "2020-12-24T00:00:00.000Z",
"id": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
}
]
}
]
I'm then trying to run an update via the elasticsearch node client like this:
for (const centre of updates) {
if (centre.indexes.length) {
await Promise.all(centre.indexes.map(async (theIndex) => {
const updated = await client.update({
index: 'centres',
type: 'doc',
id: centre.id,
body: {
script: {
lang: 'painless',
source: "ctx._source.openDays.remove(ctx._source.openDays.indexOf('openDayID'))",
params: {
"openDayID": theIndex.id
}
}
}
}).catch((err) => {throw err;});
}))
.catch((err) => {throw err;});
await client.indices.refresh({ index: 'centres' }).catch((err) => { throw err;});
}
}
When I run this though, it returns a 400 with an "array_index_out_of_bounds_exception" error:
-> POST http://localhost:9200/centres/doc/51bc77d1-b514-4f4e-85fa-412def6829f5/_update
{
"script": {
"lang": "painless",
"source": "ctx._source.openDays.remove(ctx._source.openDays.indexOf(\u0027openDayID\u0027))",
"params": {
"openDayID": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
}
}
}
<- 400
{
"error": {
"root_cause": [
{
"type": "remote_transport_exception",
"reason": "[oSsa7mn][172.17.0.2:9300][indices:data/write/update[s]]"
}
],
"type": "illegal_argument_exception",
"reason": "failed to execute script",
"caused_by": {
"type": "script_exception",
"reason": "runtime error",
"script_stack": [],
"script": "ctx._source.openDays.remove(ctx._source.openDays.indexOf(\u0027openDayID\u0027))",
"lang": "painless",
"caused_by": {
"type": "array_index_out_of_bounds_exception",
"reason": null
}
}
},
"status": 400
}
I'm not quite sure where I'm going wrong with this. Am I using the indexOf painless script correctly? Does indexOf allow for the searching of properties on objects in arrays?
I stumbled across this question and answer: Elasticsearch: Get object index with Painless script
The body of the update script needs changing like so:
Promise.all(...
const inline = `
def openDayID = '${theIndex.id}';
def openDays = ctx._source.openDays;
def openDayIndex = -1;
for (int i = 0; i < openDays.length; i++)
{
if (openDays[i].id == openDayID)
{
openDayIndex = i;
}
}
if (openDayIndex != -1) {
ctx._source.openDays.remove(openDayIndex);
}
`;
const updated = await client.update({
index: 'centres',
type: 'doc',
id: centre.id,
body: {
script: {
lang: 'painless',
inline: inline,
},
}
}).catch((err) => {throw err;});
await client.indices.refresh({ index: 'centres' }).catch((err) => { throw err;});
})).catch(... //end of Promise.all
I am not au fait with painless scripting, so there are most likely better ways of writing this e.g. breaking once the index of the ID is found.
I have also had to move the refresh statement into the Promise.all since if you're trying to remove more than one item from the array of objects, you'll be changing the document and changing the index. There is probably a better way of dealing with this too.
'openDayID' should be params.openDayID
And use removeIf:
"ctx._source.openDays.removeIf(el -> (el.id == params.openDayID))"

How to filter mongoDB in NodeJS API, checking if values are included in objects in array

I am writing REST API in NodeJS with MongoDB. Structure of the database is:
[
{
"_id": "12345",
"name": "Meal name",
"category": "dessert",
"area": "british",
"imageUrl": "https.image.jpg",
"instructions": "some instructions...",
"ingredients": [
{
"name": "salt",
"measure": "1g"
},
{
"name": "chicken",
"measure": "1"
},
{
"name": "butter",
"measure": "90g"
}, ...
]
}, ...
]
I can write a route to get data which meet one condition,
i.e.:
//getting all, when category = :category
router.get('/meals/category=:category', async (req, res) => {
try {
const meals = await Meal.find({category: req.params.category})
res.json(meals)
} catch (err) {
res.status(500).json({ message: err.message })
}
})
Here, route
'meals/category=vegetarian'
get all data with category = vegetarian.
However, I want to have route, which will filter all data by parameters: category, area, ingredients.
For example:
meals/ingredients=salt,pepper&category=dessert&area=american
should return all data, which contains salt and pepper in array, and category = dessert.
another example:
meals/area=american&category=dessert
should return all data, where area=american and category=dessert
How can I write the router.get() method to achieve that?

How to get comments data from instagram api

I have tried to get the Instagram media comments using API. I am getting empty array when I use API .I have tried sandbox live and also I make my profile public but still I get the comment data empty.
instagram.get('/media/2128588978223438874_685479/comments').then(data=> {
console.log(data); })
.catch(err => {
console.log(err);
})
I expected the output was : {
"data": [
{
"created_time": "1280780324",
"text": "Really amazing photo!",
"from": {
"username": "snoopdogg",
"profile_picture": "http://images.instagram.com/profiles/profile_16_75sq_1305612434.jpg",
"id": "1574083",
"full_name": "Snoop Dogg"
},
"id": "420"
},
...
] } .
but actual output I get was
{ data: [], meta: { code: 200 } }
media-id is just a placeholder for the real Id. Replace it and it will work.
Here is a request for getting media information, together with it's id.
instagram.get('/media/' + media_id + '/comments')
.then(data => {
console.log(data);
})
.catch(err => {
console.log(err);
})

Resources