Marklogic nodejs Api error - node.js

I have the following marklogic rest-api url :
http://marklogicserver:8060/v1/search?format=json&options=optionname&q=question
This url send me results and format them according the optionname. Everything is ok.
Now I need to do the same work with Nodejs API :
I use a querybuilder to do the same thing but my results are never formatted according to optionname.
qb.optionsName = 'optionname';
//qb.search = {q: question};
db.documents.query(
qb.where(qb.parsedFrom(‘question’))
).result( function(results) {
results.forEach(function(document) {
console.log(JSON.stringify(document,null,2));
return document;
});
}).catch(function (error){
console.log(error);
});
Although I am sure that the optioname is the right one, the system returns the following error message:
[Error: query documents: response with invalid 400 status]
message: 'query documents: response with invalid 400 status',
statusCode: 400,
body:
{ errorResponse:
{ statusCode: 400,
status: 'Bad Request',
messageCode: 'REST-INVALIDPARAM',
message: 'REST-INVALIDPARAM: (err:FOER0000) Invalid parameter: No configured options: optionname' } }

You are not passing the querybuilder to the function but a query built by it. Try creating the query and then attaching the optionsName property like this:
var query = qb.where(qb.parsedFrom(‘question’))
query.optionsName = 'optionname';
db.documents
.query(query)
.result( function(results) {
results.forEach(function(document) {
console.log(JSON.stringify(document,null,2));
return document;
});
})
.catch(function (error){
console.log(error);
});

The QueryBuilder defines the query entirely in the client. This approach gives the application complete flexibility for dynamic construction of queries and avoids the housekeeping of maintaining persisted query options.
To use query options persisted on the server, you can instead define a combined query as a JavaScript object and identify the persisted query options in that object:
http://docs.marklogic.com/jsdoc/documents.html#toc14
However, the QueryBuilder alternative is recommended.
Hoping that clarifies,

Someone from marklogic gave me the good syntax:
my query.search was malformed, if it can help somebody.
var query = qb.where();
query.optionsName = 'optionsname';
query.categories = ['none'];
query.search = {
'options':{
'search-option':['unfiltered']
},
'qtext': 'q'
};
db.documents
.query(query)
.result( function(results) {
console.log(JSON.stringify(results,null,2));
})
.catch(function (error) {
console.log(error);
});
}
Thank you very much :)

Related

How do I pass the detailed error message thrown in the node sails backend to a fetch request while calling only one method of the node res object?

I've been trying to get both the status code and the detailed error message that is passed by the sails model function "findOneOrCreate," which throws the error below when the query object doesn't conform to the model's schema
{
code: 'E_INVALID_NEW_RECORD',
details: 'Missing value for required attribute `first_opened_app_at`. Expected a value, but instead, got: undefined',
modelIdentity: 'device'
},
isOperational: true,
code: 'E_INVALID_NEW_RECORD',
details: 'Missing value for required attribute `first_opened_app_at`. Expected a value, but instead, got: undefined',
modelIdentity: 'device'
}
which is thrown in the first catch block in the sails controller method below:
logDevice: async function (req, res) {
const deviceId = req.params.deviceId
const deviceType = req.params.deviceType
Device.findOrCreate({ device_id: deviceId}, { device_id: deviceId, device_type: deviceType })
.then((err, device, wasCreated) => {
if(wasCreated) {
console.log('Logged a new device: ' + device.device_id + "("+device.device_type+")" );
res.send({ 'wasCreated': wasCreated})
}
else {
console.log('Found an existing device: ' + device.device_id + "("+device.device_type+")");
res.send({ 'wasCreated' : wasCreated })
}
})
// Some other kind of usage / validation error
.catch({ name: 'UsageError' }, err => {
console.log(err)
return res.badRequest(err);
})
// Adaptor error
.catch({ name: 'AdapterError' }, err => {
console.log(err)
res.badRequest(err);
})
// If something completely unexpected happened.
.catch(err => {
res.serverError(err);
});
},
The method that I'm using to pass the err object with the detailed error message back is the badrequest method. I'd like to keep using this method because it accurately describes the actual problem, as the request parameters provided aren't conforming to the model's schema.
But when I pass the err object into badRequest as below:
res.badRequest(err)
I'm not getting the detailed error in JSON format (in the first of the formatted code blocks in this question)
I know that if I do
res.send({err: err})
or something along those lines, I'll get the error message, but then I won't get the status codes and other useful info that I'm getting when I'm calling badRequest which are below:
bodyUsed: false
headers: Headers {map: {…}}
ok: false
status: 400
statusText: ""
type: "default"
url: "http://192.168.1.76:1337/devices/logDevice/949235da12ba6ee5/android"
_bodyBlob: Blob {_data: {…}}
_bodyInit: Blob {_data: {…}}
What's the "right" way or a good way for me to get all of the above info - both the detailed error messages and the info I'm getting with badRequest so that in my front end the response variable has all this info inside it while preferably calling a single method attached to the res object? I know I can just merge the two objects or do something like that but I want the code to be "nice" since I'll have to do something similar in a lot of different places.
fetch(global.BASE_URL+'/devices/logDevice/'+DeviceInfo.getUniqueId()+'/'+Platform.OS, {
method: "get"
})
.then( response => {
if (response.ok) {
return response.json()
}
console.log(response)
throw new Error(response);
})
.then( data => {
console.log(data)
})
.catch( err => {
console.log(err)
})
Thank you.
the first of the formatted code blocks in this question
is not a valid JSON
You need to send a valid JSON to the method:
Like the other built-in custom response modules, the behaviour of this method is customizable.
By default, it works as follows:
The status code of the response is set to 400.
Sails sends any provided error data as JSON. If no data is provided,
a default response body will be sent (the string "Bad Request").
You can make these changes in the catch block, make a valid JSON to pass it to badRequest method.
const error = {
detail: err.details,
code: err.code
}
return res.badRequest(error);

Capture a JSON GET response in a variable?

I'm using request-promise to get data from an endpoint that I have.
Is it posible to 'capture' a json response in a variable to use it anywhere?
try{
var gamer = '';//variable to capture json data
var options = {
uri: 'http://localhost:4000/gamers/'+gamer._id+'/find',
json: true
};
RequestPromise(options)
.then(function (data) {
gamer = data;//capturing response
})
.catch(function (err) {
console.log("Error saving player data !");
});
.... do something with gamer ....
}catch(err){
res.status(500).send({
message: err.message || 'An error occurred generating player teams !'
});
}
The reason that I need to do this is because actually I don't have access to the database to get that information, so my only option is to consume an API to get information through collections id's.
Your doing a lot of things correctly already. The issue is your gamer variable will get assigned the value you expect first when your promise resolves. There are many ways to skin this cat, but to get you started try performing whatever you want to perform on the gamer variable in .then(), like this:
try{
var gamer = '';//variable to capture json data
var options = {
uri: 'http://localhost:4000/gamers/'+gamer._id+'/find',
json: true
};
RequestPromise(options)
.then(function (data) {
gamer = data;//capturing response
// here is the rigth place perofrm operations on the answer, as this part of the code gets executed after promise reolves. BTW. Then you don't need variable gamer.
})
.catch(function (err) {
console.log("Error saving player data !");
});
// here is not the right place to do something with gamer as this is executed as soon as promise is initialized, not as it resolves. This means your variable will have initial value here
}catch(err){
res.status(500).send({
message: err.message || 'An error occurred generating player teams !'
});
}

REST API call using nodejs and mongodb

I am new to node.js. Following is my GET request:
router.get('/EPODS/Product/:id?', function(req, res) {
if(req.params.id){
var inputIdObj={'ProductEBM.DataArea.Product.ProductGroupID': req.params.id};
} else {
res.status(500).json({
"Error": "No input given Try give something or Check for the case sensitive in the input query fields"
});
res.end();
return;
}
db.collection('Product').findOne(inputIdObj,function(err, doc) {
if (err) {
console.log("No record found for the given input");
res.end("No record found for the input data- Please check again");
} else {
res.send(doc);
}
});
});
I am receiving null value when I hit the request in POSTMAN but the query works in MONGODB.
Please Help!
Thanks in Advance.
When you get the parameter of the GET request, you get the ID in a String format, which will not work if you use ObjectID. First, cast your param in ObjectID (you can import the object with require('mongodb').ObjectID) and so create: new ObjectID(req.params.id)

Bad Request error in uber api

I've been trying to get the uber price estimates endpoint working, but I'm stuck on an error that leads me to a blank page saying, "Bad Request." The console also says "callback not a function" but I can't seem to find out what is wrong.
My route:
// Get an upfront fare before requesting a ride
app.get('/v1.2/estimates/price', function(request, response) {
// extract the query from the request URL
var query = request.query;
// if no query params sent, respond with Bad Request
if (!query || !query.lat || !query.lng) {
response.sendStatus(400);
} else {
uber.estimates.getPriceForRouteAsync( {
"product_id": "33de8094-3dc4-4ca9-8f67-243275f57623",
"start_latitude": "38.9597897",
"start_longitude": "-94.60699369999999",
"end_latitude": "39.010969",
"end_longitude": "-94.61509899999999"
})
.then(function(res) {
log(res);
})
.error(function(err) {
console.error(err);
});
}
});
Any help is appreciated.
Please check out the README for node-uber. The method does not take a JSON object but the arguments in the method call:
uber.estimates.getPriceForRouteAsync(38.9597897, -94.606994, 39.010969, -94.615098)
.then(function(res) { console.log(res); })
.error(function(err) { console.error(err); });
Also, the product ID is not needed as the /estimates/price endpoint returns an array of estimates for each product.

KeystoneJS CloudinaryImage upload via API

There seems to be lack of documentation on this topic. I'm trying to upload an image and set it to avatar: { type: Types.CloudinaryImage } in my Keystone model.
I'm posting content as multipart form data with the following structure: avatar: <raw_data>. Here is how I handle this in my API:
exports.upload_avatar = function(req, res) {
if (!req.files.avatar) {
console.info('Request body missing');
return res.status(400).json({ message: 'Request body missing', code: 20 });
}
req.current_user.avatar = req.files.avatar;
req.current_user.save();
}
where current_user is a mongoose model. What I find confusing is how to set my CloudinaryImage type field to the data I receive in the API.
So, rather than just setting the avatar to the raw data (which would work fine for e.g. a string field), you'll need to go through the update handler, which calls to the {path}_upload special path in cloudinary image.
You should then be able to do avatar.getUpdateHandler, perhaps following this example.
I would like to share what worked for me. The process is kind of strange but by adding in this code, all of the model validation works just fine and cloudinary uploads are set.
post(req, res, next) {
const newBundle = new Bundle(); //A mongoose model
newBundle.getUpdateHandler(req).process(req.body, (err) => {
if (err) {
return res.status(500).json({
error: err.message,
});
}
return res.json(newBundle);
});
}
When posting to the endpoint, all you need to do is make sure you set your file fields to be {databaseFieldName}_upload.
Ok after some digging through the source code, I figured out a way to do that:
exports.upload_avatar = function(req, res) {
req.current_user.getUpdateHandler(req).process(req.files, {fields: 'avatar'}, function(err) {
if (err) {
return res.status(500).json({ message: err.message || '', code: 10 });
}
res.send('');
});
}
I had the following gotchas:
use getUpdateHandler to update CloudinaryImage field.
use "magic" naming for multipart form data fields you POST to your API: {field_name}_upload, which in my case would be avatar_upload.
process req.files, which is a dictionary with your field names as keys and your file data as values. req.body is empty due to some post-processing with multer.
invoke update handler on your keystone model (you need to fetch it with find first) rather than on a specific field. Then specify {fields: <>} to limit its scope, otherwise you could have some issues like validation errors trying to update the whole object.

Resources