Restangular sends empty payload for keys starting with "$" - mongodb

I'm using Restangular to connect with Mongolab. I'd like to use the following code to push an update:
var theData = {"$push":{exercises :{type: "running"}}};
Restangular.all('employees').one(user._id.$oid).customPUT(theData ,null, {apiKey: apiKey});
When I run this and look at the XHR request, the payload is always set to {}.
However, if I pull out the $, my payload looks like this:
{"push":{exercises :{type: "running"}}}
In that instance, the payload looks fine, but mongolab thinks I'm wanting to add a field named "push" instead of pushing to the excercises array since I'm not using the "$push" keyword.
I can have the "$" anywhere in the string except at the front (e.g " $push" and "push$" work) but unfortunately, that's what mongo requires in order to push an update. Is there some setting that I'm missing, or is this a bug in restangular?

yes, the $ will be striped: before the data is send, the data will be transformed with angular.toJson function:
#name angular.toJson
#function
#description
Serializes input into a JSON-formatted string. Properties with leading $ characters will be
stripped since angular uses this notation internally.
If you don't want this behavior you have to provide a transformRequest function (http://docs.angularjs.org/api/ng.$http). If your data is already json you may just write:
transformRequest: function(data){
return data;
}
the transformRequest must be provided as option during resource configuration. see
http://docs.angularjs.org/api/ngResource.$resource

Related

Access nested body property from HTTP resolver(AppSync)

I'm new to AWS AppSync and I am trying to access certain body property(from HTTP response) in my resolver's response mapping template.
For example: I am able to present the response as is via $util.toJson($ctx.result.body), but when I try to get some of the nested body properties it fails.
For example, imagine the body looks like this:
{
about:{
"firstName":"Chuck",
"lastName":"Norris"
}
}
and $util.toJson($ctx.result.body.about) returns null. Any thoughts?
I found a way extract the parsed body in the following way:
#set ($parsed_body = $util.parseJson($ctx.result.body))
And then I am able to access the properties via dot notation:
parsed_body.about.firstName
The part I was missing is $util.parseJson(<json-string>)
It seems that the body is a JSON string.

Grpc-gateway make strange wrapping of com.google.protobuf.wrappers.StringValue result

I have GRPC service with the following function:
rpc StreamMessages(StreamMessagesRequest) returns (stream google.protobuf.StringValue) {
option (google.api.http) = {
post: "/messages:stream"body: "*"
};
}
With grpc-gateway behind it.
Once I have collection of 3 strings: "msg1", "msg2", "msg3" - wrapping every one as com.google.protobuf.wrappers.StringValue and returning as stream.
On GRPC side everything fine, but when I'm trying to execute REST request via gateway the issue happens:
According to documentation, Json representation of google.protobuf.StringValue is just JsonString, so expected streaming result is:
"msg1"
"msg2"
"msg3"
But it returns unexpected format instead:
{"result":"msg1"}
{"result":"msg2"}
{"result":"msg3"}
Question: How can I cause gateway to return the expected?
In order to obtain what you're looking for you need to use the protobuf specific package for the json marshaling. Instead of the standard one, use this one: google.golang.org/protobuf/encoding/protojson.
The interface is the same, but it correctly marshals StringValues to strings when an actual value is provided and the fields get ignored if the StringValue pointer is nil.

How to receive json in Dancer?

I am very new to Perl framework Dancer. As of now I have a get http listener working. I have an Angular framework trying to post a json string to Dancer. How can I retreive the json and perhaps assign it to a scalar variable ($json).
get '/games' => sub {
header 'Access-Control-Allow-Origin' => '*';
&loadgames();
return $games;
};
post '/newgame' => sub {
header 'Access-Control-Allow-Origin' => '*';
#what should i put here to retrieve the json string
#I plan to pass the json string to a sub to convert to XML
};
I am not sure If I chose Dancer as backend framework that will get and post data.
Thanks for the help!
If your HTTP request has a JSON body (Content-type: application/json) rather than being an HTML form post, then you probably want something like this:
post '/url-path' => {
my $post = from_json( request->body );
# do something with the POSTed data structure
# which would typically be a hashref (or an arrayref)
# e.g.: schema->resultset('Widget')->create($post);
}
The from_json routine is one of the DSL Keywords provided by Dancer.
Dancer provides the params keyword for accessing route, body, and query parameters. You want a body parameter. Exactly which body parameter you want will depend on the name of the field you posted it to the route with (look at your form or your ajax request).
my $json_string = params('body')->{$field_name}
You can also use param, if you don't have any conflicting parameter names in the route or query parameters.
Once you have the json, remember it's just a string at the moment. You might want to read it into a perl data structure: Dancer provides from_json for this purpose.
As an aside: I notice in your get route, you call a function loadgames in void context, and then return a variable you haven't declared (or perhaps you have set it as a global - but do you need it to be a global?). I recommend beginning each perl file with use strict; to pick up issues like this. I suspect you probably just want to use the return value of loadgames as your return value.

Vertx router configuration

I am a novice with vertx so maybe I am doing something wrong. I am trying to implement the following routes:
router.get("/api/users/").handler(this::getUsers);
router.route("/api/users/:username*").handler(this::checkUsername);
router.get("/api/users/:username/").handler(this::getUser);
router.put("/api/users/:username/").handler(this::addUser);
router.get("/api/users/:username/assignments/").handler(this::getAssignments);
router.post("/api/users/:username/assignments/").handler(this::addAssignment);
router.route("/api/users/:username/assignments/:assignmentId/").handler(this::checkAssignmentId);
router.get("/api/users/:username/assignments/:assignmentId/").handler(this::getAssignment);
Is this the correct way to avoid duplicating this logic in all handlers?
I am trying to chain handlers, where the checkUsername handler reads the username parameter from the path, tries to find a corresponding user, and puts that user in the context. If no user is found, a statuscode 400 is returned. Otherwise the next handler is called. I would like to apply the same principle to the assignmentId parameter.
While trying to implement this, I believe I found a problem with the path, more specifically the trailing slash and star. The documentation states that trailing slashes are ignored. This is not the behavior when there is a parameter in the path. In that case the trailing slash matters. If the path definition contains one and the request does not, vertx returns a 404. It does not make a difference whether or not the parameter is at the end of the path or in the middle.
The same goes for paths ending with a star. This functionality does not work when the path contains a parameter.
You can use a regular expression to avoid duplication of the checkUsername validation check. What I would do is I would have a method like this to check if the username is valid:
private void checkUsername(RoutingContext routingContext){
//The "param0" is the capture group of the regular expression. See the routing config below.
if (isValidUsername(routingContext.request().getParam("param0"))){
routingContext.next();
} else {
routingContext
.response()
.setStatusCode(400)
.end();
}
}
To check the assignment ID I would do something similar:
private void checkAssignmentId(RoutingContext routingContext){
if (isValidAssignmentId(routingContext.request().getParam("assignmentId"))){
routingContext.next();
} else {
routingContext
.response()
.setStatusCode(400)
.end();
}
}
Try to avoid trailing slashes in your paths. I would change the routing handler assignments to be something like this:
router.get("/api/users").handler(this::getUsers);
//By the way, you really want to be using a POST request when adding users just to stick to the principles of REST.
//When you are sending a POST request there is no need to put the username in the URI. You can have it in the request body.
//Please ensure you validate this username using the same validation helper used in your other validations.
router.post("/api/users").handler(this::addUser);
//Use regular expression to match all "/api/users/:username*" URIs
router.routeWithRegex("\\/api\\/users\\/([^\\/]+)").handler(this::checkUsername);
router.get("/api/users/:username").handler(this::getUser);
router.get("/api/users/:username/assignments").handler(this::getAssignments);
router.post("/api/users/:username/assignments").handler(this::addAssignment);
router.route("/api/users/:username/assignments/:assignmentId").handler(this::checkAssignmentId);
router.get("/api/users/:username/assignments/:assignmentId").handler(this::getAssignment);

Using save or put with Restangular results in "undefined" being included in URL

I am using Restangular to download an object, update it and then attempt to save back to the server using the save method. Here is the code that retrieves the object:
Restangular.one("survey", surveyID).getList().then (
function (response) {
$scope.survey = response[0];
}
);
This sets $scope.survey to a properly "restangularized" object, with the fields that come back from the GET request, along with the methods like save, put, etc.
If I then invoke the following function after making some edits to the $scope.survey object:
$scope.saveChanges = function () {
$scope.survey.save();
};
restangular tries to use the URL /survey/1/undefined for the PUT request (1 is the correct ID for the object).
My survey object doesn't have an id field (it's surveyID instead), and so I suspected this might be the problem. However, replacing the surveyID field with an id field changed the URL to be /survey/1/undefined/1
I have stripped down the object returned by the GET request to be just primitives, and this does not change the situation.
Why is the incorrect route being generated?
II discovered the problem was actually with the REST service; when called with GET /surveys/1, it was returning an array with a single object in it, rather than returning the object itself.
I think this caused restangular to think that a collection was being accessed (note that I was having to call getList rather than get in order to get a properly restangularized object).