First important information: I’m new to laravel, so your patience is appreciated.
I’m currently migrating a framework of mine to laravel, so I’m in the early stages.
Currently, I’m trying to set up an API endpoint to make small changes on some records. I’ve already managed to set up a API for inserting records and works perfectly. However, for setting up an API for small changes (patch), I’m having difficulties, probably because I’m not fully familiar with laravel’s Request class.
My successful insert set up looks like this:
\routes\api.php
Route::post('/categories/',[ApiCategoriesInsertController::class, 'insertCategories'], function($insertCategoriesResults) {
return response()->json($insertCategoriesResults);
})->name('api.categories.insert');
\app\Http\Controllers\ApiCategoriesInsertController.php
// some code
public function insertCategories(Request $req): array
{
$this->arrCategoriesInsertParameters['_tblCategoriesIdParent'] = $req->post('id_parent');
// some code
}
With this set up, I’m able to retrieve “id_parent” data set through POST.
So, I tried to do exactly the same architecture for patch, but doesn’t seem to work:
\routes\api.php
Route::patch('/records/',[ApiRecordsPatchController::class, 'patchRecords'], function($patchRecordsResults) {
return response()->json($patchRecordsResults);
})->name('api.records.patch');
\app\Http\Controllers\ApiRecordsPatchController.php
// some code
public function patchRecords(Request $req): array
{
$this->arrRecordsPatchParameters['_strTable'] = $req->post('strTable');
// some code
}
In this case, I´m using postman (PATCH request), testing the data in the "Body tab" with key "strTable" and value "123xxx" and I´m receiving “strTable” as null.
Any idea of why this is happening or if I should use another method in the Request class?
Thanks!
You can access parameters on the Request object using one of the following methods:
$req->strTable;
// or
$req->input('strTable');
The input method also accepts a second parameter which will be used as the default return value if the key is not present in the Request.
If you want to check whether or not the Request contains a value before you attempt to access it, you can use filled:
if ($req->filled('strTable')) {
// The request contains a value
}
Turns out that the way I had set up was in fact working and retrieving data:
$req->post('strTable');
The problem was in how I was testing it. In postman, there are several options to configure:
form-data
x-www-form-urlencoded
raw
binary
I had already switched to x-www-form-urlencoded to test it, but I forgot to fill the “key” and “value” information again. I didn’t realize that the fields blank as we switch between them.
Summing it up: It works when x-www-form-urlencoded selected but doesn’t work with form-data selected. Don’t know what the difference between them yet, but I’ll research it further.
By the way, it worked also with the suggestion from Rube Hart:
Related
I have a Laravel Application and another APP making calls via API to Laravel. These 2 projects are separated.
Laravel and App have their own multilanguage system. They work independently but uses the same key translations.
So my idea was that all Laravel responses must be translations key, like: 'messages.success'.
With this response, the App can translate it.
All of these are working fine.
The problem appeared when I started working with Laravel Requests for validating forms.
In this case, the validation errors are automatically translated so the App receives the response translated with the default language of the Laravel application.
So what can I do?
I thought with 2 ideas but I don't know if they can work.
1: Passing the language into params. Don't know if it can work, how can I set the language before Laravel validates the Request?
2: Override the functionality of Requests to return messages without translate, so instead of "Felicidades" return "messages.success". I really like this approach. But how can I do it for all the rules? Overriding the messages function like this:
public function messages()
{
return [
'unique' => 'validation.unique'
];
}
For every rule works... but I feel bad.
Another approaches?
What is the best way to fix this problem?
I would suggest that you use this hacky solution in 2 lines of code. Go to /resources/lang/{code}/validation.php. You can see that it returns an array of messages by default. Modify it like so:
// Replace return in the first line
$ret = [
/* all the translations go here as normal */
];
// Add this as the last line. This will replace all values with their keys.
return array_combine(array_keys($ret), array_keys($ret));
After that you can use validation as per usual and you'll get validation message keys instead of messages. Cheers and hope this helps.
Im trying to call cloud function from parse.com at Restask in Tasker
I already configured custom headers, parameter, etc.
But it always returns 400. And return body empty. Not sure why.
I'm doing something similar to what you're trying to do and just managed to POST an object into parse. The problem you're facing is that your request's body is empty (should be a JSON)
You can set that in RESTask's settings under "Custom body".
I initially had problems with variables inside the body, but after talking to John from RESTask, he said that the variables work:
it won't work, however, when you use the "test" function inside
RESTask, as there is no context of a task
Good luck and let us know what you've built .)
Z.
I have read a lot of answers relating to how to dynamically add forms to an model formset in Django and can successfully implement that. However, I would now like to submit the formset with AJAX. This is mostly working now but I have an issue that I can't find a solution to in any other answer:
If you dynamically add a form to the formset, you give it a new form id number that is one larger than the maximum the form currently has and you also increment the management TOTAL_FORMS count by one. The newly added form then saves successfully as a new object.
I am trying to submit by AJAX so the user can continue editing without having the page refresh. The formset saves fine but any dynamically added forms are now existing objects. To account for this I need to increment the INITIAL_FORMS count on the management form when the save is successful. Easy enough. However, I've also realised I need to give the newly created objects an ID since they now exist in the database.
How can I get my view to tell me the ID of the new objects in its response to the AJAX call? Or is there a better way of looking at this?
Django forms and formsets are intended for classic browser-based posting of data. Though they can definitely be made to work with Javascript, the more you want to part from the normal behavior, the more complex it gets.
Depending on your requirements, you might start thinking about dropping it and switch to Javascript + REST endpoint. Of course, if you need progressive enhancements and you are required to have it work without javascript, that's not an option.
In any case, you want to have a customized view for posting from JS, so that you can get the result back and parse it easily in your AJAX handler. Probably some JSON.
There are several approaches you could take.
Have your AJAX send data to a different URL. This is pertinent if you have an API or are planning to build one at some point. So your form, when submitted normally, will do its old-style processing but your AJAX will talk to the API endpoint instead.
For instance, your form send to https://example.com/myform, but your Javascript code talks to REST api at https://example.com/api/v1/mymodel/ (sending PUT, POST and DELETE requests as appropriate).
Or if you don't have an API and building one seems overkill, you may just alter your view so it formats its output differently depending on whether the data is being submitted in the regular way or using AJAX.
You'd go about it like this:
class MyFormView(.....):
def render_to_response(self, context, **kwargs):
if self.request.is_ajax():
return self.render_to_json(context, **kwargs)
return super().render_to_response(context, **kwargs)
def render_to_json(context, **kwargs):
data = {
# see below!
}
return HttpResponse(
content=json.dumps(data).encode('ascii'),
content_type='application/json',
)
This is just an outline. You need to ensure is_ajax will detect it properly (see django doc). And you need to properly build data from context: extract the things you want to send back to your JS code and put them in the dict.
You will find it's manageable if you just do this for one, maybe two views in your project, but very quickly you'll want to have a small API instead, especially given how easy it is to build one with packages such as Django REST framework.
In your view, where you save the object, AFTER the save, the object.id will contain the new id for the object, which you can return via json or however you want in your ajax response, and then yes you will need to fill that into the formset row so that it will be submitted the next time.
One thing you have to watch out for is that django expects all existing rows to be at the top of the formset, and any new rows to be at the bottom. Otherwise, the formset save will complain about missing id's. So if you're doing any kind of sorting in your javascript, you can't do that.. unless you do quite a bit of fixing of all the field names etc in the formset. The formset code uses the numbers in the management form to determine which rows to insert and which rows to update, it does not do it on the basis of whether or not an id is present. Unfortunately...
Scenario:
I have a Board model in my Rails server side, and an Android device is trying to post some content to a specific board via a POST. Finally, the server needs to send back a response to the Android device.
How do I parse the POST manually (or do I need to)? I am not sure how to handle this kind of external request. I looked into Metal, Middleware, HttpParty; but none of them seems to fit what I am trying to do. The reason I want to parse it manually is because some of the information I want will not be part of the parameters.
Does anyone know a way to approach this problem?
I am also thinking about using SSL later on, how might this affect the problem?
Thank you in advance!! :)
I was trying to make a cross-domain request from ie9 to my rails app, and I needed to parse the body of a POST manually because ie9's XDR object restricts the contentType that we can send to text/plain, rather than application/x-www-urlencoded (see this post). Originally I had just been using the params hash provided by the controller, but once I restricted the contentType and dataType in my ajax request, that hash no longer contained the right information.
Following the URL in the comment above (link), I learned the how to recover that information. The author mentions that in a rails controller we always have access to a request variable that gives us an instance of the ActionDispatch::Request object. I tried to use request.query_string to get at the request body, but that just returned an empty string. A bit of snooping in the API, though, uncovered the raw_post method. That method returned exactly what I needed!
To "parse it manually" you could iterate over the string returned by request.raw_post and do whatever you want, but I don't recommend it. I used Rack::Utils.parse_nested_query, as suggested in Arthur Gunn's answer to this question, to parse the raw_post into a hash. Once it is in hash form, you can shove whatever else you need in there, and then merge it with the params hash. Doing this meant I didn't have to change much else in my controller!
params.merge!(Rack::Utils.parse_nested_query(request.raw_post))
Hope that helps someone!
Not sure exactly what you mean by "manually", posts are normally handled by the "create" or "update" methods in the controller. Check out the controller for your Board model, and you can add code to the appropriate method. You can access the params with the params hash.
You should be more specific about what you are trying to do. :)
We are using the Dynamic Script Tag with JsonP mechanism to achieve cross-domain Ajax calls. The front end widget is very simple. It just calls a search web service, passing search criteria supplied by the user and receiving and dynamically rendering the results.
Note - For those that aren’t familiar with the Dynamic Script Tag with JsonP method of performing Ajax-like requests to a service that return Json formatted data, I can explain how to utilise it if you think it could be relevant to the problem.
The service is WCF hosted on IIS. It is Restful so the first thing we do when the user clicks search is to generate a Url containing the criteria. It looks like this...
https://.../service.svc?criteria=john+smith
We then use a dynamically created Html Script Tag with the source attribute set to the above Url to make the request to our service. The result is returned and we process it to show the results.
This all works fine, but we noticed that when using IE the service receives the request from the client Twice. I used Fiddler to monitor the traffic leaving the browser and sure enough I see two requests with the following urls...
Request 1: https://.../service.svc?criteria=john+smith
Request 2: https://.../service.svc?criteria=john+smith&_=123456789
The second request has been appended with some kind of Id. This Id is different for every request.
My immediate thought is it was something to do with caching. Adding a random number to the end of the url is one of the classic approaches to disabling browser caching. To prove this I adjusted the cache settings in IE.
I set “Check for newer versions of stored pages” to “Never” – This resulted in only one request being made every time. The one with the random number on the end.
I set this setting value back to the default of “Automatic” and the requests immediately began to be sent twice again.
Interestingly I don’t receive both requests on the client. I found this reference where someone is suggesting this could be a bug with IE. The fact that this doesn’t happen for me on Firefox supports this theory.
Can anyone confirm if this is a bug with IE? It could be by design.
Does anyone know of a way I can stop it happening?
Some of the more vague searches that my users will run take up enough processing resource to make doubling up anything a very bad idea. I really want to avoid this if at all possible :-)
I just wrote an article on how to avoid caching of ajax requests :-)
It basically involves adding the no cache headers to any ajax request that comes in
public abstract class MyWebApplication : HttpApplication
{
protected MyWebApplication()
{
this.BeginRequest += new EventHandler(MyWebApplication_BeginRequest);
}
void MyWebApplication_BeginRequest(object sender, EventArgs e)
{
string requestedWith = this.Request.Headers["x-requested-with"];
if (!string.IsNullOrEmpty(requestedWith) && requestedWith.Equals(”XMLHttpRequest”, StringComparison.InvariantCultureIgnoreCase))
{
this.Response.Expires = 0;
this.Response.ExpiresAbsolute = DateTime.Now.AddDays(-1);
this.Response.AddHeader(”pragma”, “no-cache”);
this.Response.AddHeader(”cache-control”, “private”);
this.Response.CacheControl = “no-cache”;
}
}
}
I eventually established the reason for the duplicate requests. As I said, the mechanism I chose to use for making Ajax calls was with Dynamic Script Tags. I build the request Url, created a new Script element and assigned the Url to the src property...
var script = document.createElement(“script”);
script.src = https://....”;
Then to execute the script by appending it to the Document Head. Crucially, I was using the JQuery append function...
$(“head”).append(script);
Inside the append function JQuery was anticipating that I was trying to make an Ajax call. If the type of element being appended is a Script, then it executes a special routine that makes an Ajax request using the XmlHttpRequest object. But the script was still being appended to the document head, and being executed there by the browser too. Hence the double request.
The first came direct from the script – the one I intended to happen.
The second came from inside the JQuery append function. This was the request suffixed with the randomly generated query string argument in the form “&_=123456789”.
I simplified things by preventing the JQuery library side effect. I used the native append function...
document.getElementByTagName(“head”).appendChild(script);
One request now happens in the way I intended. I had no idea that the JQuery append function could have such a significant side effect built in.
See www.enhanceie.com/redir/?id=httpperf for further discussion.