Multiple get API in MEAN.IO (Express, Angular) - angularjs

In traditional REST API, we should define our API like this:
GET /api/things -> get all
POST /api/things -> create
GET /api/things/:id -> get one
PUT /api/things/:id -> update
DELETE /api/things/:id -> delete
How should i define another 'get one' endpoint for querying data by any other field other than id? For example:
GET /api/things/:title -> get one by title (this sure does not work since the api isn't aware of URL parameter names)
GET /api/things/title/:title ? this does not work for me at all..
GET /api/things?title=whatever (this cannot be defined at all. When i write this in my index.js:
router.get('?title=whatever', controller.getByTitle);
I get this:
SyntaxError: Invalid regular expression: /^?title=whatever\/?$/: Nothing to repeat
at RegExp (native)

ID should be an unique identifier. Given one ID, you should return one resource at most. That's why an URI like GET /api/things/:id makes sense.
For other properties which may or may not be unique, you can have more than one result, so use the GET /api/things endpoint and pass query parameters : /api/things?title=mytitle.
app.get('/api/things', function (req, res) {
console.log(req.query.title); //mytitle
ThingModel.find({
title: req.query.title
}, function (err, things) {
res.send(things);
});
});

Related

Postman passing an array as a parameter

Using a Postman to retrieve data from our project management platform that provides collections (Teamwork)
I retrieve a first list of project ID from the Get request using the following code in the Test of that first Get request :
`var jsonData = JSON.parse(responseBody);
var list = (jsonData.projects).length;
var a=[];
for (var i = 0; i < list; i++)
{
var counter = jsonData.projects[i];
IDs=counter.id
a.push(IDs)
}
postman.setEnvironmentVariable("id", a);`
That create a variable id which contains a list of id.
After that, I want to go through each of these id in the following request (replacing {id})
{{Domain}}/projects/{id}/rates.json
Domain is set in the environment variable and is working.
What code and where do i need to put it (Pre-script? Test?) so I can go through the list? That second get request would give me the employee rates in each project (identified by those id)
Thanks for your help
If you want to use the list of variables you extract from the first GET in URLs for subsequent calls, then I think you would need to use the pm.sendRequest option in the 'Test' tab of your first GET.
There is a really good example in this thread:
How to run one request from another using Pre-request Script in Postman
Note: The pre-req tab is executed before the API call is made and the test tab is executed after the API call is made.
Also, "postman." is using the old API, you would benefit from using the newer API which is "pm." so for example;
pm.environment.set("variable_key", "variable_value");
More info on this can be found here:
https://learning.postman.com/docs/sending-requests/variables/

Node.js multible get functions with different parameters

I have the following Node.js Express routes
app.get('/api/admin/elements/:type', elements.getElementsByType);
app.get('/api/admin/elements/:_id', elements.getElement);
the elements funtions are:
getElementsByType : function(req, res) {
element.find({
type : req.params.type
}, function(err, elements) {
if (err) {
return err;
}
res.json(elements);
});
},
getElement : function(req, res) {
var file = "/thatulborooj-data/elements/" + req.params._id + ".json";
jsonfile.readFile(file, function(err, obj) {
if (err) {
res.json([]);
} else {
res.json(JSON.parse(obj));
}
});
}
when I all $http.get('/api/admin/elements/' + scope.element._id) fro angularJS it always all the first get, how can I make difference between them or set parameter type
express.js doesn't know the name of the variable that you pass to it, because it is a webserver which listen to some addresses.
In your case the first route says:
If someone goes on /api/admin/elements/{{whatever}} call the function elements.getElementsByType() and assign whatever to the variable type
The second route says the same thing, just to call another function and assign the value to the var _id.
A possible solution is to have two different routes:
app.get('/api/admin/elements/type/:type', elements.getElementsByType);
app.get('/api/admin/elements/id/:_id', elements.getElement);
Another possible solution is, if you are sure id is always an int and type is never an int is to call just one function and choose what to do checking the param type:
app.get('/api/admin/elements/:value', elements.getElementsByType);
getElementsByType : function(req, res) {
if (isNaN(req.params.value)) {
// this is a type
} else {
//this is an id
}
But I want to highlight it is important you understand why your example doesn't work.
I cannot explain how web works in just one answer, but let me highlight some things:
express.js listens on your server to request to a port, as a webserver. You can say to express.js which routes you want to listen: all routes that aren't specified will reply with 404 (or 405 if you ask for a method that doesn't exist on a resource that exists, like POST on /api/admin/elements/{{whatever}} in your example).
So, when you specify a route, you have two components:
a fixed part, which is the address, and it is always the same (like /api/admin/elements/), and a part which value can change.
You say to express.js which part can change using the : notation. For express.js, whatever is in an URL between the /: and the next / has to be passed in the req.params object with the name you specify.
Let's do some examples:
/a/:a/b/:b/c/:c
This address will response to each call you do to `/a/{{param1}}/b/{{param2}}/c/{{param3}}
So you will have a req.params object with these 3 values:
req.param = {
a: 'param1',
b: 'param2',
c: 'param3',
}
You do not like a, b, and c as names? Me neither, so let's change that:
/a/:artemis/b/:betelgeuse/c/:cassidy
Then the req.params object will be:
req.param = {
artemis: 'param1',
betelgeuse: 'param2',
cassidy: 'param3',
}
But for express.js it is the same thing, it cannot choose what it is basing only on the value.
Now, an example a bit more complicated:
if you have
/a/:a and /a/b for express.js can be a bit confusing (but also for whoever uses your APIs, so please do not do this).
Now, how this works is up to the order you declared the routes.
If you did /a/:a and then /a/b the function associated to /a/b will never be called. express.js takes the address requested and check each route if it has a match. So if you call /a/b express.js finds /a/:a (that means an /a/ and a thing after this and thinks the b is a valid value for the variable a).
But if you declare the /a/b before the /a/:a express.js will reach before the /a/b (that means a route that is exactly /a/b) then it will be matched first.
Assuming that _id should match an ObjectId, you can make the route handler explicitly match those:
app.get('/api/admin/elements/:_id([a-f0-9]{24})', elements.getElement);
app.get('/api/admin/elements/:type', elements.getElementsByType);
Just be sure that the _id route is declared before the (more general) type route.
Caveat: this breaks if you use types that match ObjectId's.

Using userId with Gatling DSL

I am using session.userId to parametrize my test requests like this:
exec(http("get request")
.get((s:Session) => "somebaseUrl/" + s.userId.toString ))
Is it possible to get sesion userId differently, so my request addresses are more DRY, eg I won't have to use lambda?
I tried using gatling DSL:
exec(http("get request")
.get("somebaseUrl/${userId}")
but then I get: No attribute named 'userId' is defined error
I could just calculate some random id to my tests, but why when gatling already does this.
Only solution that I came up with is saving userId to some different attribute like this:
exec((s:Session) => s.set("user_id",s.userId)),
exec(http("test").get("${user_id}"))
but that doesn't seem right, and you have to make sure to call the set before all other requests.
The userId is some internal details. Gatling Expression language only exposes Session attributes, ie the attributes Map content.
Either use the first way you described, with a function, or don't use Gatling internals and set your own UUID attribute (feeder, exec(function), etc).
To avoid using gatling internals you could use a feeder:
var userId = 0
feed(Iterator.continually(Map("userId" -> {
userId += 1
userId}.toString)))

Is it possible to perform a Restangular GET with multiple query parameters?

I've been attempting to perform a Restangular GET with multiple query parameters (for simple pagination) and it doesn't seem possible--at least with what I'm trying to do. Here's what I'm attempting to do:
Restangular.all('elevation').get({ pageParam: page, pageSizeParam: pageSize }).then(function(data) {
console.log(data);
});
WIth the expected response looking something like:
{ totalRecords: 233, elevations: {...} }
This does not work and results in the following:
GET http://localhost:24287/elevation/[object%20Object] 404 (Not Found)
I also attempting utilizing customGET as well which results in the same problem as above.
The only way I'm actually able to pass multiple query parameters is by using getList. Unfortunately when utilizing the getList unsurprisingly the following error is thrown:
Error: Response for getList SHOULD be an array and not an object or something else
To resolve this issue, the Restangular documentation states in the My response is actually wrapped with some metadata. How do I get the data in that case? section that I need to use addResponseInterceptor which I've done like so:
RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
var newResponse = [];
if(response.data.totalRecords !== undefined) {
newResponse.elevationData= {};
newResponse.elevationData.totalRecords = response.data.totalRecords;
newResponse.elevationData.elevations = response.data.elevations;
}
return newResponse;
});
After jumping through hoops this convoluted solution does in fact work. Is there not an easier way to simply call Restangular's get with multiple query parameters and get an object returned?
At this point, it would be a magnitude easier to take Restangular out of the question and simply use the $http service like so:
$http.get('http://localhost:24287/elevation?page=' + page + '&pageSize=' + pageSize).then(function(result) {
console.log(result.data.totalRecords);
console.log(result.data.elevations);
});
Though I really want to figure out a better way to do this with Restangular.
Any ideas would be greatly appreciated! Thanks!
That's deadly simple, querying a ressource URL without an id, even with specific query params, and returning a single object is just not RESTful.
Error: Response for getList SHOULD be an array and not an object or something else
It's precisely telling you the truth : your query could return an array, because you haven't specified a unique identifier (everything else is not unique).
At this point, it would be a magnitude easier to take Restangular out of the question and simply use the $http service
Definately, since Restangular focuses on RESTful resource proxying, or you're gonna have to tweak it (interceptors, customGET, ...)

node.js, restify - handle a parameter of type array

I have a node.js server with restify. I want to send it a get request that has an array of names in it. I think the request should look like this (but I am not sure about it):
/users?names=bob,joe,michael,joey
Is this query correct?
How do I get the names I send on the node.js server?
The W3C recommendation is that one key can be repeated multiple times with multiple values:
GET /users?names=bob&names=joe&names=michael&names=joey
Good systems will be designed to handle this format of data and be able to recognize multiple keys to group them within an array.
You do not need to specify query variables in your route:
// perform: GET /users?names=bob&names=joe&names=michael&names=joey
server.get('/users', function (req, res) {
// All your query vars from the GET request are in req.query
res.json(req.query.names);
});

Resources