How to decorate a request with parameters? - siesta-swift

How can I decorate all request adding to all request, custom parameters?
I want to add the param key to all request.
configure("**", description: "auth") {
$0.decorateRequests(with: { (res, req) -> Request in
?? what to add here?
})
}
I tried to add:
res.withParams(... etc )
But I need to return the request.
In the example from the doc, it only add header not parameters to the body.

decorateRequests is the wrong API for this. Its purpose is to add to or surround the behavior of requests already fully formed, not to alter the request itself.
What you are looking for is mutateRequests, which allows you to change any part of the raw URLRequest (including the URL itself, which includes the params) before Siesta takes control of it.
Unfortunately, URLRequest’s Obj-C-era API for working with params is a bit cumbersome — but it can do the job. If you want to add foo=bar to all requests, and if you want that to work properly whether or not the URL already has HTTP parameters, the safest way to do it is to break the URL into its components, add a new URLQueryItem for foo=bar, then reconstruct the URL:
service.configure {
$0.mutateRequests { req in
guard
let url = req.url,
var components = URLComponents(url: url, resolvingAgainstBaseURL: true)
else {
return
}
components.queryItems =
(components.queryItems ?? [])
+ [URLQueryItem(name: "foo", value: "bar")]
req.url = components.url
}
}
Note that this is the correct approach for adding query params globally across a set of resources, overriding their individual logical URLs. It sounds like this is indeed what you’re after.
However, if you (or any others reading this) want instead to create a resource whose URL happens to have query params that are part of what make it unique — the far more common use case — then resource.withParam(…) is the right thing to use.
There is a subtle difference between these approaches: resource.withParam("foo", "bar") returns a new resource with a different URL, logically distinct from resource, that can have different latest data, different requests in progress, etc. On the other hand, the mutateRequests basically says, “Whatever you think the URL is, I secretly add these extra params when talking to the server — but the extra params do not make it a distinct resource.” Be careful which one you’re using.

Related

url as parameters? in ASP.NET CORE

Is there a way to read url as parameters?
for example url could be:
downloadSomething.com/data/json/something
And the method:
[HttpGet]
public async Task<Data> Data(string type, string otherParameter)
{
...
I know it's not a good practice.. I just want to know if is it possible.
Thx for help :)
I'm not sure exactly what you're asking here. The way routing works by default would allow this particular example.
[HttpGet("data/{type}/{otherParameter}")]
If you're talking about actually taking part of the path as a param, you can use the catch-all param, but it must be last param in the route (as it will obviously swallow everything).
[HttpGet("data/{**stuff}")]
That would then set the param stuff with the full path: json/something.

Previous GET parameters being unintentionally preserved in POST request

As of current I navigate to a view using a GET request, looking something like this:
/batches/install?Id=2&ScheduledDate=07.29%3A12
From there, I send a POST request using a form (where I include what data I wish to include in the request.
Furthermore I set the forms action to "Create" which is the action I wish to send the request to.
My issue is the fact that sending this request keeps the GET arguments in the POST url, making it look the following:
../batches/Create/2?ScheduledDate=07.29%3A12
I do not want this since:
1: it looks weird
2: it sends data I do not intend it to send in this request
3: if my model already has a property named "id" or "scheduledDate" the unintentional GET parameters will get bound to those properties.
How can I ignore the current GET parameters in my new POST request?
I just want to send the form POST data to the url:
../batches/create
(without any GET parameters)
How would this be done?
As requested, here is my POST form:
#using (var f = Html.Bootstrap().Begin(new Form("Create")))
{
//inputs omitted for brevity
#Html.Bootstrap().SubmitButton().Style(ButtonStyle.Success).Text("Create batch")
}
Note that I use the TwitterBootstrapMVC html helpers (https://www.twitterbootstrapmvc.com/), althought this really shouldn't matter.
As requested, to sum up:
I send a get request to : /batches/install?Id=2&ScheduledDate=07.29%3A12.
Through the returned view I send a POST request to: /batches/create.
However the previous get parameters get included in the POST request URL making the POST request query: /batches/Create/2?ScheduledDate=07.29%3A12 (which is NOT intended).
This is not a great Idea though, but will give you what you want.
[HttpPost]
public ActionResult Create() {
//do whatever you want with the values
return RedirectToAction("Create", "batches");
}
This is a "Feature" of MVC that was previously reported as a bug (issue 1346). As pointed out in the post, there are a few different workarounds for it:
Use named routes to ensure that only the route you want will get used to generate the URL (this is often a good practice, though it won't help in this particular scenario)
Specify all route parameters explicitly - even the values that you want to be empty. That is one way to solve this particular problem.
Instead of using Routing to generate the URLs, you can use Razor's ~/ syntax or call Url.Content("~/someurl") to ensure that no extra (or unexpected) processing will happen to the URL you're trying to generate.
For this particular scenario, you could just explicitly declare the parameters with an empty string inside of the Form.
#using (var f = Html.Bootstrap().Begin(new Form("Create").RouteValues(new { Id = "", ScheduledDate = "" })))
{
//inputs omitted for brevity
#Html.Bootstrap().SubmitButton().Style(ButtonStyle.Success).Text("Create batch")
}

Use dynamic url for Backbone Collection

Backbone configure url once for all when a Collection is created. Is there a way to change this url later?
The following sample shows 2 POST at /product and 2 POST at /product/id/stock. The last POST won't work, Backbone concatenate the id and try to PUT it, but I don't know why.
products.create({ name: 'American Pastoral', price: 8 });
products.create({ name: 'The Grapes of Wrath', price: 10 });
products.each(function(product) {
var id = parseInt(product.get('id'));
stocks.setId(id);
stocks.create({ id: id, quantity: 12 });
}
The stock collection:
Backbone.Collection.extend({
url: function() {
return this.url;
},
parse : function(resp) {
return resp.stock;
},
setProduct: function(id) {
this.url = '/product/'+id+'/stock';
}
});
This won't work.
Backbone.js will use the url of the model when saving existing models. Its not quite clear what you are trying to do -- I don't know what stocks is, for instance. Anyway, your code probably needs to look similar to the below and you should not be dynamically changing the url:
Product = Backbone.Model.extend({
url: function() {
return '/product/' + id + '/stock';
}
});
ProductList = Backbone.Collection.extend({
model: Product,
url: '/product'
}):
Backbone.js will then use collection url for creates and the model url for saves. I think you need to leave the url alone and let backbone's default functionality handle it.
I have run into what is essentially the same problem. It seems that Backbone's pattern is to lock down relative URI's in models and collections and allow the framework to use these to build final the final URI for a given resource. This is great for Restful URI's templates that don't change. But in a pure RESTful service you would expect lists of relative URI's to come down as part of a given resource. There are many reasons why you might need to do this, obvious one is if the URI for a resource moves.
As far as I can tell Backbone has no way of easily cleanly handling this. In the question above my workaround is to essentially redefine the models url method using OLN. You would do this while fetching a collection or initializing it for the first time. Basically build the logic to handle URI lists yourself.
I know this is an old question, but it took me a bit to determine how to solve it for my problem. In the manual under the fetch operation there is this tidbit:
jQuery.ajax options can also be passed directly as fetch options, so to fetch a specific page of a paginated collection: Documents.fetch({data: {page: 3}})
The object being passed to the data parameter is added as a URL GET variable. So URL would turn into URL?page=3 or URL?x=1&page=3 if there were existing variables already.

Grails catch all url mapping with exceptions

I am trying to create a mock rest service. There are basically two components to this. I need a controller with actions and views that allows me to create ResourceMappings where I create a mapping between a uri and a mock response that I will pass back. The second component is a catch-all Grails url mapping for every other url so that when they hit the uri of this application they will be sent to my catch all controller that will return the mapped response that they created earlier.
For example... I go to the url http://someserver.com:1234/restMapping/list. This url is the exception to the catch all rule. It takes me to some views that allow me to create a rest uri mapping. Here I create the mapping /mockservice/test and give it the response "This is a test" with a content type of text/plain. Now, if I go to the url http://someserver.com:1234/mockservice/test I should hit the catch all that sends me to a controller that returns a page with the content type text/plain and the response "This is a test".
I have tried the following and it does not seem to work. Does anyone have any ideas?
static mappings = {
"/$control/**" {
controller = "catchAllHandler"
action = "index"
constraints {
control(validator: {!['restMapping','css','js','images'].contains(it)})
}
}
"/$controller/$action?/$id?"{
}
"/"(controller:"restMapping", action="index")
"500"(view:'/error')
}
An interesting thing to note is that when I get rid of ** and add in tons of extra variables like $s1?/$s2?/$s3? etc then it does seem to work. The problem is that I don't know how long the uri is that I am trying to map so I would rather use the ** to catch everything exception the few exceptions that I have.
I finally figured it out. I needed to include WEB-INF in my list to exclude. I now use the static excludes field as well as the validator to exclude specific controller urls.
class UrlMappings {
static excludes = ["/images/*","/css/*","/js/*","/WEB-INF/*"]
static mappings = {
"/restResourceMapping/$action?/$id?"{
controller = "restMapping"
}
"/$control/?**" {
controller = "catchAllHandler"
action = "index"
constraints {
control(validator: {!['restMapping'].contains(it)})
}
}
"/"(controller:"restMapping", action="index")
"500"(view:'/error')
}
}
I decided to just exclude all url mappings that should never be any of my rest urls. These included /images, /css, /js, and /WEB-INF. I can now create urls of any length and have them go to my catch all controller. If the person goes to the base url or the restMapping url set then they will be taken to the crud pages where they can create new rest resource mappings. If I want to create any other controllers and views that I want to go around the catch all controller I can simply add it to my validator and make them process normally.
Also you might notice that I am using a ? in the catch all right after the /. This seems to make it so my catch all works with urls that only have one word after the server name as in http://server.com:1234/something.
I am not sure about this, but I think the order in which the URL mappings are defined is important. So try listing the URL mapping for your special cases at the beginning of the mappings closure and then list the general ones (the one that uses **). Do let me know if this works :)

How to get Url Hash (#) from server side

I know on client side (javascript) you can use windows.location.hash but could not find anyway to access from the server side. I'm using asp.net.
We had a situation where we needed to persist the URL hash across ASP.Net post backs. As the browser does not send the hash to the server by default, the only way to do it is to use some Javascript:
When the form submits, grab the hash (window.location.hash) and store it in a server-side hidden input field Put this in a DIV with an id of "urlhash" so we can find it easily later.
On the server you can use this value if you need to do something with it. You can even change it if you need to.
On page load on the client, check the value of this this hidden field. You will want to find it by the DIV it is contained in as the auto-generated ID won't be known. Yes, you could do some trickery here with .ClientID but we found it simpler to just use the wrapper DIV as it allows all this Javascript to live in an external file and be used in a generic fashion.
If the hidden input field has a valid value, set that as the URL hash (window.location.hash again) and/or perform other actions.
We used jQuery to simplify the selecting of the field, etc ... all in all it ends up being a few jQuery calls, one to save the value, and another to restore it.
Before submit:
$("form").submit(function() {
$("input", "#urlhash").val(window.location.hash);
});
On page load:
var hashVal = $("input", "#urlhash").val();
if (IsHashValid(hashVal)) {
window.location.hash = hashVal;
}
IsHashValid() can check for "undefined" or other things you don't want to handle.
Also, make sure you use $(document).ready() appropriately, of course.
[RFC 2396][1] section 4.1:
When a URI reference is used to perform a retrieval action on the
identified resource, the optional fragment identifier, separated from
the URI by a crosshatch ("#") character, consists of additional
reference information to be interpreted by the user agent after the
retrieval action has been successfully completed. As such, it is not
part of a URI, but is often used in conjunction with a URI.
(emphasis added)
[1]: https://www.rfc-editor.org/rfc/rfc2396#section-4
That's because the browser doesn't transmit that part to the server, sorry.
Probably the only choice is to read it on the client side and transfer it manually to the server (GET/POST/AJAX).
Regards
Artur
You may see also how to play with back button and browser history
at Malcan
Just to rule out the possibility you aren't actually trying to see the fragment on a GET/POST and actually want to know how to access that part of a URI object you have within your server-side code, it is under Uri.Fragment (MSDN docs).
Possible solution for GET requests:
New Link format: http://example.com/yourDirectory?hash=video01
Call this function toward top of controller or http://example.com/yourDirectory/index.php:
function redirect()
{
if (!empty($_GET['hash'])) {
/** Sanitize & Validate $_GET['hash']
If valid return string
If invalid: return empty or false
******************************************************/
$validHash = sanitizeAndValidateHashFunction($_GET['hash']);
if (!empty($validHash)) {
$url = './#' . $validHash;
} else {
$url = '/your404page.php';
}
header("Location: $url");
}
}

Resources