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

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).

Related

play framework - redirecting with querystring

I am Using the play Framework 2.7.x
I have a Formular on my controller.list() with a view, let's call it "index". After you click "send" it open's controller.add() where it dos some stuff and then redirects back to controller.list(). If there was an error in the formular (a requiered field was empty) I need the queryString, which was send to controller.add() also redirected to controller.list()
The problem ist that if I do stuff like just passing the request, i get an error that it's not possible to add arguments.
public Result list(Http.Request request)
{
// .... stuff with foo, while foo is an Form<foo> Object
// ... foo.bindFromRequest(request)
ok(views.html.index.render(foo))
}
public Result add(Http.Request request)
{
// not allowed to add request as an argument. only empty is allowed.
return Results.redirect(controllers.routes.Controller.list(request));
}
I would like to just redirect the Form object, so I can handle the error in the controller.list() and not have to generate an extra view for the controller.add(). If I do everything inside controller.list() there is no problem with this code, but I like to use the controller.add() method instead.
Is the an option? except passing every querystring key and value by hand.
After I searched yesterday the half the day, I found something interessting today.
you are not allowed to use a default parameter with =. You have to use an optional default parameter with ?= inside the routes!!!!!
you can implement QueryStringBindable so it's a bit easier to bind the query String. But you still have to bind them "by hand".

{guzzle-services} How to use middlewares with GuzzleClient client AS OPPOSED TO directly with raw GuzzleHttp\Client?

My middleware need is to:
add an extra query param to requests made by a REST API client derived from GuzzleHttp\Command\Guzzle\GuzzleClient
I cannot do this directly when invoking APIs through the client because GuzzleClient uses an API specification and it only passes on "legal" query parameters. Therefore I must install a middleware to intercept HTTP requests after the API client prepares them.
The track I am currently on:
$apiClient->getHandlerStack()-push($myMiddleware)
The problem:
I cannot figure out the RIGHT way to assemble the functional Russian doll that $myMiddleware must be. This is an insane gazilliardth-order function scenario, and the exact right way the function should be written seems to be different from the extensively documented way of doing things when working with GuzzleHttp\Client directly. No matter what I try, I end up having wrong things passed to some layer of the matryoshka, causing an argument type error, or I end up returning something wrong from a layer, causing a type error in Guzzle code.
I made a carefully weighted decision to give up trying to understand. Please just give me a boilerplate solution for GuzzleHttp\Command\Guzzle\GuzzleClient, as opposed to GuzzleHttp\Client.
The HandlerStack that is used to handle middleware in GuzzleHttp\Command\Guzzle\GuzzleClient can either transform/validate a command before it is serialized or handle the result after it comes back. If you want to modify the command after it has been turned into a request, but before it is actually sent, then you'd use the same method of Middleware as if you weren't using GuzzleClient - create and attach middleware to the GuzzleHttp\Client instance that is passed as the first argument to GuzzleClient.
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Command\Guzzle\GuzzleClient;
use GuzzleHttp\Command\Guzzle\Description;
class MyCustomMiddleware
{
public function __invoke(callable $handler) {
return function (RequestInterface $request, array $options) use ($handler) {
// ... do something with request
return $handler($request, $options);
}
}
}
$handlerStack = HandlerStack::create();
$handlerStack->push(new MyCustomMiddleware);
$config['handler'] = $handlerStack;
$apiClient = new GuzzleClient(new Client($config), new Description(...));
The boilerplate solution for GuzzleClient is the same as for GuzzleHttp\Client because regardless of using Guzzle Services or not, your request-modifying middleware needs to go on GuzzleHttp\Client.
You can also use
$handler->push(Middleware::mapRequest(function(){...});
Of sorts to manipulate the request. I'm not 100% certain this is the thing you're looking for. But I assume you can add your extra parameter to the Request in there.
private function createAuthStack()
{
$stack = HandlerStack::create();
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
return $request->withHeader('Authorization', "Bearer " . $this->accessToken);
}));
return $stack;
}
More Examples here: https://hotexamples.com/examples/guzzlehttp/Middleware/mapRequest/php-middleware-maprequest-method-examples.html

How to access invoke response object variable in following steps of assembly

the assembly of my API Connect API contains two invokes. The first is calling an internal routing API to get some routing information. The response of this routing API should not be passed to the second invoke.
If I do not configure a 'response object variable' in the invoke of the routing API, the original request body is overwritten and the second API gets the result from the routing API as request body. And if I specify a 'response object variable' in the routing invoke, I can not access the content (json) of this variable in the following steps.
How can I solve this issue?
Thx 4 help.
Rather than relying on reading the request object, you can read from your configured 'response object variable' later on in the flow. For instance, if your first invoke has a response object variable set to 'resp1', you can access the JSON payload using '$(resp1.body)' later on in the flow. Using this technique will allow you to store the response of each invoke in a separate object, avoiding the overwriting issue. These response object variables can be read just like any other context variable in the flow.
For more info, check out these links in the Knowledge Center:
Invoke Policy: https://www.ibm.com/support/knowledgecenter/en/SSMNED_5.0.0/com.ibm.apic.toolkit.doc/rapim_ref_ootb_policyinvoke.html
Context Variables:
https://www.ibm.com/support/knowledgecenter/SSMNED_5.0.0/com.ibm.apic.toolkit.doc/capim_context_references.html
I don't understand this part:
[...] "And if I specify a 'response object variable' in the routing
invoke, I can not access the content (json) of this variable in the
following steps." [...]
Why can't you access the content of this variable in the following steps?
Save copy of the request...
... that you received. What I'd do is always save a copy of the data received in the invoke to a processed variable instead of the (raw) original request.
In your GatewayScript try something like this:
let objRequest = apim.getvariable("request");
let body = null;
Here I recommend you to change the body (if json) to a standard js object
if(objRequest && objRequest.hasOwnProperty("body")){
try{
body = JSON.parse(objRequest.body);
}catch(e){
body = objRequest.body;
}
}
Remember to stringify the complete object before saving it as global variable. Is the only way to store it (because you can only store a string value in this kind of variables)
apim.setvariable("objRequest", JSON.stringify(objRequest));
Retrieve copy of the request...
...that you have saved in global variables you can get it from any other GatewayScript that you want this way:
let objRequest = JSON.parse(apim.getvariable("objRequest"));
Be careful not to assign an existent name to the apim.setvariable(name, value) because if you use "request" as name instead of "objRequest" (or other), you'll be replacing the original request element, and we don't want that to happen.
If you need to set or retrieve the status.code...
...you can do it with:
let statusCode = objRequest.body.status.code;

Protractor: Extracting URL value from an element and using URL to open new browser instance

I am trying to do following:
get element(div in this case) containing a URL for eg.
`ele = "www.xyz.com".
Use getAttribute('value') or getText() to
grep URL
Use this URL to fork new instance of browser and GET the
URL
newBrowser = browser.forkNewDriverInstance();
ele.getAttribute('value').then(function(val){
newBrowser.get(val);
});
and I am getting following error:
RangeError: Maximum call stack size exceeded
Second method I tried was without promise and got the error saying that url should be string and not object.
As in:
var url = ele.getText();
newBrowser.get(url);
Is there a way to convert the object returned by getText() into a string and store into variable so that it can be used in some other place.
In your second appraoch, ele.getText() will give you a promise that needs to be resolved. You can resolve the promise on the second approach by using something like this-
ele.getText().then(function(url){
newBrowser.get(url);
})
If this does not work, try printing url with console.log(url). I think it is an object array and you need to get the item you need by referring to the index like url[0] or url[1]. try using console log to print all these values.

HTML form POST method with querystring in action URL

Lets say I have a form with method=POST on my page.
Now this form has some basic form elements like textbox, checkbox, etc
It has action URL as http://example.com/someAction.do?param=value
I do understand that this is actually a contradictory thing to do, but my question is will it work in practice.
So my questions are;
Since the form method is POST and I have a querystring as well in my URL (?param=value)
Will it work correctly? i.e. will I be able to retrieve param=value on my receiving page (someAction.do)
Lets say I use Java/JSP to access the values on server side. So what is the way to get the values on server side ? Is the syntax same to access value of param=value as well as for the form elements like textbox/radio button/checkbox, etc ?
1) YES, you will have access to POST and GET variables since your request will contain both. So you can use $_GET["param_name"] and $_POST["param_name"] accordingly.
2) Using JSP you can use the following code for both:
<%= request.getParameter("param_name") %>
If you're using EL (JSP Expression Language), you can also get them in the following way:
${param.param_name}
EDIT: if the param_name is present in both the request QueryString and POST data, both of them will be returned as an array of values, the first one being the QueryString.
In such scenarios, getParameter("param_name) would return the first one of them (as explained here), however both of them can be read using the getParameterValues("param_name") method in the following way:
String[] values = request.getParameterValues("param_name");
For further info, read here.
Yes. You can retrieve these parameters in your action class.
Just you have to make property of same name (param in your case) with there getters and setters.
Sample Code
private String param;
{... getters and setters ...}
when you will do this, the parameters value (passed via URL) will get saved into the getters of that particular property. and through this, you can do whatever you want with that value.
The POST method just hide the submitted form data from the user. He/she can't see what data has been sent to the server, unless a special tool is used.
The GET method allows anybody to see what data it has. You can easily see the data from the URL (ex. By seeing the key-value pairs in the query string).
In other words it is up to you to show the (maybe unimportant) data to the user by using query string in the form action. For example in a data table filter. To keep the current pagination state, you can use domain.com/path.do?page=3 as an action. And you can hide the other data within the form components, like input, textarea, etc.
Both methods can be catched in the server with the same way. For example in Java, by using request.getParameter("page").