I am trying to do post a list,
the data that I have look like this:
{
'entity_id': '1',
'genre_entity_ids':['6','7','8']
}
I have been trying all kinds of combinations:
entity_id=1&genre_entity_ids[0]=6&genre_entity_ids[1]=7&genre_entity_ids[3]=8
entity_id=1&genre_entity_ids[]=6&genre_entity_ids[]=7&genre_entity_ids[]=8
entity_id=1&genre_entity_ids=6&genre_entity_ids=7&genre_entity_ids=8
...
But none of them is accepted by the server.
Please what am I doing wrong??
EDIT: they need to be form urlencoded
Related
So I'm having an interesting issue with Laravel HTTP Client while trying to hit an API endpoint for PayPal.
I can get Laravel HTTP Client working on all my endpoints that POST with data, but this one endpoint that only requires headers (no data is passed in the body) fails with an error.
{
"name":"INVALID_REQUEST",
"message":"Request is not well-formed, syntactically incorrect, or violates schema.",
"debug_id":"609388c4ddfe4",
"details":[
{
"field":"\/",
"location":"body",
"issue":"INVALID_SYNTAX",
"description":"MALFORMED_REQUEST_JSON"
}
],
"links":[
{
"href":"https:\/\/developer.paypal.com\/docs\/api\/orders\/v2\/#error-INVALID_SYNTAX",
"rel":"information_link",
"encType":"application\/json"
}
]
}
When I hit the same endpoint in Postman everything works fine
My method for hitting the endpoint looks like this
public static function capture($order)
{
$token = Paypal::fetchToken();
$api_url = config('services.paypal.api_url') . '/v2/checkout/orders/' . $order['id'] . '/capture';
$headers = [
'Content/Type' => 'application/json',
];
$response = Http::withToken($token)
->withHeaders($headers)
->post($api_url)
->json();
return $response;
}
I have tried passing an empty array in the post request like this ->post($api_url, []) but that did not work either.
I have hardcoded the $api_url just in case I made a mistake with my formatting with variables. Resulted in the same issue.
I have tried changing the 'Content/Type' in the header to 'none'. This did not work either and also doesn't make sense because I have this same header set in postman and it works fine (PayPal docs also says to pass this content/type)
Based on the error I am receiving I can only assume the request is hitting the endpoint correctly, but either the HTTP wrapper or guzzle itself is adding something to the body when I leave it blank and it is causing PayPal to throw the error. Don't really know what else I can try though.
Is there a parameter I am overlooking for specifying an empty body on a post request?
Any help is appreciated.
Looking at the source I found the following solution
$response = Http::withToken($token)
->withHeaders($headers)
->send("POST", $api_url)
->json();
I had the same issue, but I fixed it with a simple trick.
I found the solution on https://docs.guzzlephp.org/en/stable/request-options.html#json.
This code should work.
$response = Http::withToken($token)
->withHeaders($headers)
->post($api_url,['json' => []])
->json();
The empty array is now seen as an empty array/body in JSON.
Our front end application always expects a certain json format for the result, something like:
{
success: true,
errors: [],
responseObject: ...
}
Say I want to return a list of users, that list would be a in the responseObject. Now I would like to be able to just return this list from the restcontroller and have something like a controller advice wrap the list in this response object. However as I understand I cannot use the controller advice in this case. Is there a way to do this?
You can use for this purpose Filter. You can get your list of users from the response object, wrap in your desired model structure and change in response.
Example:
https://medium.com/#sportans300/fiddling-with-httpresponses-in-java-2a269cd5a474
Does anyone know how to set a simple js Object to Parse.Object's field with type 'file' and save it successfully?
I have a model like
{...
picture: 'file',
...
}
I upload a file via server side and get an {name,url} object.
Send it to front-end as JSON.
After that I'm trying to use this JSON as picture
{...
picture: {name,url},
...
}
via POST request to the server(model.save(params)) but have just
{ code: 111,
message: 'Invalid file url: "http://s3.amazonaws.com/files.parsetfss.com/4d46bc83-d162-4d44-8462-d695f008f787/tfss-8c096482-2b88-4509-a99c-4c99ae57d51d-cat.jpg"' }
There is an approach without duplicate pictures like Cloud Code: Creating a Parse.File from URL?
Artyom24 was right.
I've removed s3.amazonaws.com/ and now everything is ok.
Web API allows me to capture the body of a POST request in a JObject:
$.post('/api/Query/DoSomething', { Foo: "one", Bar: 4 });
public string Post(JObject data)
{
// data is populated
}
However the same technique does not work with a get request and URI parameters.
$.get('/api/Controller', { Foo : "one", Bar : 4 });
public string Get([FromUri]JObject data)
{
// data is empty
}
Any workaround here?
It doesn't work because a GET request does not have a body, and hence no content type. Therefore, Web API does not know that you have JSON in your URL. You have a few choices:
Pass your data as query string parameters, as is traditionally done in GET requests, and change your method to accept those parameters individually, or in a regular class (POCO).
Change your GET method to accept a string instead of a JObject, then use JSON.Net to deserialize it manually, e.g. JObject obj = JObject.Parse(data);
If you're feeling ambitious, you might be able to implement a custom binder to do this.
My recommendation is option 1. Traditionally, a GET method is just intended to look something up, so you really should only be passing IDs and simple query options anyway. It is unusual to be passing JSON data in a URL. Also the length of URLs can be limited by some browsers. If you find you are needing to pass JSON data, use POST (or PUT) instead.
You can create an object and bind to it using the FromUri.
Check out this solution which I am using https://stackoverflow.com/a/49632564/2463156.
EDIT: See below for my current problem. The top portion is a previous issue that I've solved but is somewhat related
I need to modify the input values passed to my controller before it actually gets there. I am building a web app that I want to be able to support multiple request input types (JSON and XML initially). I want to be able to catch the input BEFORE it goes to my restful controller, and modify it into an appropriate StdClass object.
I can't, for the life of me, figure out how to intercept and modify that input. Help?
For example, I'd like to be able to have filters like this:
Route::filter('json', function()
{
//modify input here into common PHP object format
});
Route::filter('xml', function()
{
//modify input here into common PHP object format
});
Route::filter('other', function()
{
//modify input here into common PHP object format
});
Route::when('*.json', 'json'); //Any route with '.json' appended uses json filter
Route::when('*.xml', 'xml'); //Any route with '.json' appended uses json filter
Route::when('*.other', 'other'); //Any route with '.json' appended uses json filter
Right now I'm simply doing a Input::isJson() check in my controller function, followed by the code below - note that this is a bit of a simplification of my code.
$data = Input::all();
$objs = array();
foreach($data as $key => $content)
{
$objs[$key] = json_decode($content);
}
EDIT: I've actually solved this, but have another issue now. Here's how I solved it:
Route::filter('json', function()
{
$new_input = array();
if (Input::isJson())
{
foreach(Input::all() as $key => $content)
{
//Do any input modification needed here
//Save it in $new_input
}
Input::replace($new_input);
}
else
{
return "Input provided was not JSON";
}
});
Route::when('*.json', 'json'); //Any route with '.json' appended uses json filter
The issue I have now is this: The path that the Router attempts to go to after the filter, contains .json from the input URI. The only option I've seen for solving this is to replace Input::replace($new_input) with
$new_path = str_replace('.json', '', Request::path());
Redirect::to($new_path)->withInput($new_input);
This however leads to 2 issues. Firstly I can't get it to redirect with a POST request - it's always a GET request. Second, the data being passed in is being flashed to the session - I'd rather have it available via the Input class as it would be with Input::replace().
Any suggestions on how to solve this?
I managed to solve the second issue as well - but it involved a lot of extra work and poking around... I'm not sure if it's the best solution, but it allows for suffixing routes similar to how you would prefix them.
Here's the github commit for how I solved it:
https://github.com/pcockwell/AuToDo/commit/dd269e756156f1e316825f4da3bfdd6930bd2e85
In particular, you should be looking at:
app/config/app.php
app/lib/autodo/src/Autodo/Routing/RouteCompiler.php
app/lib/autodo/src/Autodo/Routing/Router.php
app/lib/autodo/src/Autodo/Routing/RoutingServiceProvider.php
app/routes.php
composer.json
After making these modifications, I needed to run composer dumpautoload and php artisan optimize. The rest of those files are just validation for my data models and the result of running those 2 commands.
I didn't split the commit up because I'd been working on it for several hours and just wanted it in.
I'm going to hopefully look to extend the suffix tool to allow an array of suffixes so that any match will proceed. For example,
Route::group(array('suffix' => array('.json', '.xml', 'some_other_url_suffix')), function()
{
// Controller for base API function.
Route::controller('api', 'ApiController');
});
And this would ideally accept any call matching
{base_url}/api/{method}{/{v1?}/{v2?}/{v3?}/{v4?}/{v5?}?}{suffix}`
Where:
base_url is the domain base url
method is a function defined in ApiController
{/{v1?}/{v2?}/{v3?}/{v4?}/{v5?}?} is a series of up to 5 optional variables as are added when registering a controller with Route::controller()
suffix is one of the values in the suffix array passed to Route::group()
This example in particular should accept all of the following (assuming localhost is the base url, and the methods available are getMethod1($str1 = null, $str2 = null) and postMethod2()):
GET request to localhost/api/method1.json
GET request to localhost/api/method1.xml
GET request to localhost/api/method1some_other_url_suffix
POST request to localhost/api/method2.json
POST request to localhost/api/method2.xml
POST request to localhost/api/method2some_other_url_suffix
GET request to localhost/api/method1/hello/world.json
GET request to localhost/api/method1/hello/world.xml
GET request to localhost/api/method1/hello/worldsome_other_url_suffix
The last three requests would pass $str1 = 'hello' and $str2 = 'world' to getMethod1 as parameters.
EDIT: The changes to allow multiple suffixes was fairly easy. Commit located below (please make sure you get BOTH commit changes to get this working):
https://github.com/pcockwell/AuToDo/commit/864187981a436b60868aa420f7d212aaff1d3dfe
Eventually, I'm also hoping to submit this to the laravel/framework project.