search api in loopback nodejs - node.js

I have a need to implement this api in loopback nodejs
https://myapi.com/part_numbers?part_number=1245,6787,89490,940044...
Any ideas on how to go about it ?
The path after part_number should accept atleast 100 partnumbers and then return me the result.
All the documentation that i have looked at in loopback talks abut only sending a get request to something like https://myapi.com/part_numbers?part_number=1245
but not about sending for multiple comma separated values
Any ideas on how do i build this endpoint using loopback and nodejs I am using mysql as the backend datastore.

Disclaimer: I am a maintainer of LoopBack and co-author of the pull request adding support for character-delimited arrays in input arguments.
LoopBack provides a feature flag to enable comma-delimited array values in input arguments, this flag was added by https://github.com/strongloop/strong-remoting/pull/142. (Unfortunately it's not documented yet.)
How to use it:
1) Configure allowed delimiters in your server/config.json:
{
"restApiRoot": "/api",
// ...
"rest": {
"handleErrors": false,
// ADD THE FOLLOWING LINE
"arrayItemDelimiters": [","],
// original content - keep it around:
"normalizeHttpPath": false,
"xml": false
},
// ...
}
2) Define a custom remote method (see docs) accepting an argument of type "array of numbers". For example, assuming you have a model called PartNumbers already defined:
PartNumbers.get = function(numbers) {
// replace this code with your implementation
// here, we simply return back the parsed array
return Promise.resolve(numbers);
};
PartNumbers.remoteMethod('get', {
accepts: {
arg: 'part_numbers',
type: ['number'],
required: true,
},
// modify "returns" to match your actual response format
returns: {
arg: 'data',
type: 'object',
root: true,
},
http: {verb: 'GET', path: '/'},
});
3) Start you application, open API Explorer at http://localhost:3000/explorer and give your new method a ride!

Related

Node.js Query Parameters for Smartsheet API

I am trying to send include parameters with a get-sheet request smartsheet.sheets.getSheet(options) using the Node.js sdk. The API documentation is vague on how to add the include parameters in the API call.
I found a Smartsheet Developers Blog post Demystifying Query Parameters in the Smartsheet API that provides more guidance, but the Node.js example code they provide is invalid javascript:
// Set options
var options = {
queryParameters: {
include: "attachments",
include: "source",
includeAll: true
}
};
// List sheets
smartsheet.sheets.listSheets(options)
.then(function(response) {
...
In the above code the last include query parameter will override all of the prior values and you will be left with a options variable that looses the "attachements" parameter:
queryParameters: {
include: "source",
includeAll: true
}
To me the obvious solutions would be for include to take an array like:
include: ["attachments", "source"],
Any suggestions?
Outside of using the SDK whatever values needed for the include query string are added to the URL as a comma separated list. The SDK will take the value you provide for the include parameter of the queryParameters object and add that as the value for the include query string and append it to the URL.
Instead of providing the include parameter multiple times in the queryParameters object or providing an array you would give a single string value for include with all of the options you wish to use comma separated.
For example, a GET Sheet request that asks for the source info and attachments to be included would look like this:
const options = {
id:<SHEET_ID>,
queryParameters : {
include: 'source,attachments',
includeAll: true
}
}
smartsheet.sheets.getSheet(options)
.then(sheet => {
console.log(sheet);
})
.catch(err => {
console.log(err);
})
Note, the includeAll query string is for pagination and can be used separately to have all rows of the sheet included in the response.
Also, if you are running test requests in your console and set logLevel: 'info' when creating your Smartsheet client with the access token you can see the URL being used for the request get printed out above the sheet data response and it will show you how the URL is being structured.

Default value in remote methods in loopback framework

After writing application logic in particular model.js file I have defined remote method for that particular model as I want to expose that api and I want to accept some arguments in which one of the argument is object type and I want to give default value to that argument
I have done like this
{
arg: 'whereConditionFilter',
type: 'object',
default: {},
required: true
},
But I am confused is this the correct way to do this thing.
You can use beforeRemote hook for that.
Model.beforeRemote( 'yourCustomRemoteMethod', function( ctx, instance, next) {
let whereConditionFilter = ctx.req.params.whereConditionFilter;
/*Modify your whereConditionFilter here and resign it*/
})

Loopback: Cannot call Notification.create(). The create method has not been setup. The PersistedModel has not been correctly attached to a DataSource

I am using Loopback and the push component. When calling Notification.create() I get the error:
Cannot call Notification.create(). The create method has not been setup.
The PersistedModel has not been correctly attached to a DataSource!
I'm just running the basic example server 2.0. In code I am trying to create a Notification. What's the problem?
I too got the same problem when trying to use login function of User model.
Got it fixed after an hour of hit and trial.
Answer: I extended User model to MyUser model (No coding inside this model, just used it as a wrapper) and inside Hotel.js (in my case a business class where i use to authenticate user before accessing hotel details) created a remoteMethod for login
code:
Hotel.auth=function(uname,pwd, cb)
{
Hotel.app.models.MyUser.login({username: uname, password: pwd}, function (err, token) {
if(err)
cb(null,err);
else
cb(null,token);
});
}
Hotel.remoteMethod(
'auth',
{
accepts:
[
{arg: 'uname', type: 'string',required: true},
{arg: 'pwd', type: 'string',required: true}
],
returns: {arg: 'Response Message', type: 'string'}
}
);
This works!
This one is pretty old, but just to put something up here. Without seeing your setup my guess is that the model you are using is not connected to any data source, or one that is not written properly. The default connector is in-memory and does implement this method correctly. Check your server/model-config.json file and find the entry for Notification and check what you have for the data source.

LoopBack Remote Methods and Access to Model Data

I've been working on this for hours and I'm completely lost, because the loopback documentation is not helpful.
I'm trying to write application logic into a model. The documentation for that is here. Unfortunately, the example doesn't demonstrate anything useful other than passing an external value into the remote method and returning it again. I'd like to understand how to run a query in this context and access model data, but I have searched for hours and not been able to find documentation on even these simple tasks. Maybe I'm just looking in the wrong places. Can anyone help?
Typically, you can accomplish most things you'd want to do such as querying and accessing model data (CRUD operations) through the built-in methods that all models get; see http://docs.strongloop.com/display/LB/Working+with+data. Defining a remote method (custom REST endpoint) for these would be redundant.
You access the standard model CRUD Node APIs (e.g. myModel.create(), myModel.find(), myModel.updateAll() ) in the remote method code if you want to.
You may also find further related examples in https://github.com/strongloop/loopback-example-app-logic
Here's an example using the Getting Started app https://github.com/strongloop/loopback-getting-started app. It defines a remote method that takes a number arg and prints the name of the coffeeshop with that ID to the console:
This code is in common/models/coffeeshop.js:
module.exports = function(CoffeeShop) {
...
// Return Coffee Shop name given an ID.
CoffeeShop.getName = function(shopId, cb) {
CoffeeShop.findById( shopId, function (err, instance) {
response = "Name of coffee shop is " + instance.name;
cb(null, response);
console.log(response);
});
}
...
CoffeeShop.remoteMethod (
'getName',
{
http: {path: '/getname', verb: 'get'},
accepts: {arg: 'id', type: 'number', http: { source: 'query' } },
returns: {arg: 'name', type: 'string'}
}
);
};
You can use the API Explorer to load http://0.0.0.0:3000/explorer/#!/CoffeeShops/getName then enter a number (there are only three coffee shops in the app initially) as the query param and hit "Try It Out!"
Or just GET a URL like http://0.0.0.0:3000/api/CoffeeShops/getid?id=1
Rand
I finally discovered my problem. Object properties must be loaded in a callback of the function calling the CRUD operation. The following syntax worked for me:
module.exports = function (TestModel) {
TestModel.testRemoteMethod = function (id, name, cb) {
TestModel.findOne({where: {id: id}}, function(err, modelInstance) {
//modelInstance has properties here and can be returned to
//the API call using the callback, for example:
cb(null, {"name": modelInstance.name});
}
}
TestModel.remoteMethod('testRemoteMethod',
//..rest of config

Validation errors in custom instance or static methods in a Mongoose model

I have a basic Mongoose model with a Meeting and Participants array:
var MeetingSchema = new Schema({
description: {
type: String
},
maxNumberOfParticipants: {
type: Number
},
participants: [ {
type: Schema.ObjectId,
ref: 'User'
} ]
});
Let's say I want to validate that the number of participants added doesn't exceed the maxNumberOfParticipants for that meeting.
I've thought through a few options:
Custom Validator - which I can't do because I have to validate one attribute (participants length) against another (maxNumberOfParticipants).
Middleware - i.e., pre-save. I can't do this either because my addition of participants occurs via a findOneAndUpdate (and these don't get called unless I use save).
Add validation as part of my addParticipants method. This seems reasonable, but I'm not sure how to pass back a validation error from the model.
Note that I don't want to implement the validation in the controller (express, MEAN.js stack) because I'd like to keep all logic and validations on the model.
Here is my addParticipants method:
MeetingSchema.methods.addParticipant = function addParticipant(params, callback) {
var Meeting = mongoose.model('Meeting');
if (this.participants.length == this.maxNumberOfParticipants) {
// since we already have the max length then don't add one more
return ????
}
return Meeting.findOneAndUpdate({ _id: this.id },
{ $addToSet: { participants: params.id } },
{new: true})
.populate('participants', 'displayName')
.exec(callback);
};
Not sure how to return a validation error in this case or even if this pattern is a recommended approach.
I wouldn't think that's it's common practice for this to be done at the mongoose schema level. Typically you will have something in between the function getting called and the database layer (your schema) that performs some kind of validation (such as checking max count). You would want your database layer to be in charge of just doing simple/basic data manipulation that way you don't have to worry about any extra dependencies when/if anything else calls it. This may mean you'd need to go with route 1 that you suggested, yes you would need to perform a database request to find out what your current number of participants but I think it the long run it will help you :)

Resources