How to validate JSON in Laravel API regardless of parameters order? - php

I am making an iOS app with Alamofire as the HTTP Request handler, and in the iOS App, i want to send a JSON payload to a Laravel API server. More or less, the JSON structure looks like this:
{
"test_data": "Any data is here",
"another_data": "Another data is here"
}
Now, in my Laravel project, I've been implementing a validation rule, basically to validate that those 2 params in the JSON is required and in a type of String. Here's my code to implement the validator:
$validator = Validator::make($request->all(), [
'test_data' => 'required|string',
'another_data' => 'required|string'
]);
if ($validator->fails()) {
return redirect()->route('dataNotComplete');
}
The confusion is that this works, but it only works in order. Hence, if the JSON structure becomes flipped like this:
{
"another_data": "Another data is here",
"test_data": "Any data is here"
}
Validator will fails the test, even though the data is technically correct. How do I make the validator doesn't care about data ordering, or do another library exist for validating JSON specifically? I just want to validate the data of each params, not including the order of the data on the JSON Payload. Any thoughts or idea will be appreciated! Thank you!
P.S. I read from here that JSON order of parameters shouldn't matter, so that's that.

Related

Laravel Request can't get values of some key

I am trying to retrieve some part of request() in my Form Request class named StoreApplicantLanguage.php. The request key called 'languages' and it has an array of objects containing a key-value pair to be stored in my `applicant_languages' table.
Here is my JSON request from Postman:
{
"languages": [
{
"language": "English",
"capability": 1
}
]
}
Looks normal right?! But, when I'm trying to get the values of the languages key like this:
$requestLanguages = request()->languages;
dd($requestLanguages);
, it shows null.
I tried to restart my server, do php artisan config:cache, but none are works. But when I change the key name in the request object to language, it works!
Also, the request object has another named field like families, and I can get the values inside by doing request()->families.
I have no idea at all how this can be happen. Anyone can explain my case, please!
Thanks in advance!
Edit: From Malkhazi Dartsmelidze's answer I realized that I misstyped the question. I didn't write comma after '1' value in my JSON request
It works fine on my system.
Maybe you that's because you are passing invalid json.
{
"languages": [
{
"language": "English",
"capability": 1
}
]
}
Try passing this JSON (I deleted last comma after '1')
Also note that Request is object and there is properties that are used already and $request variable can return it. You can use $request->get('languages') to get parameter from request

Laravel Request Validation of an object

I would like to filter some data coming from an API payload in which i have to check if some certain part of the data is an object, such as this:
"object"{
"propety":value,
"another_propety":value,
}
I wanna be sure that the "object" that comes from the payload is actually an object, which holds properties and not an integer, neither, an array or any other type...but an object. Is there any way i can solve this by using Laravel's native validator i have to create a custom rule?
Thank you
Considering the laravel lifecycle, By the time the request payload reaches validation the object has already changed to a php array, use the below to validate your key.
$this->validate($request, [
'object' => 'required|array',
'object.property' => 'required|string',
]);
https://laravel.com/docs/5.8/validation#rule-array
also in case it is somehow going to remain a JSON object, check the official documentation for doing so -> https://laravel.com/docs/5.8/validation#rule-json
This will help you identify the object key as JSON while the request gets vaildated.

Laravel is returning different data types in axios with same code

I am really confused about my situation right now.
As you can see I have this controller in laravel that separates the data from a collection by filtering the collection
$bankedQuestions = $questions->whereNotIn('id', $sortedQuestionsID)->all();
$sortedQuestions = $questions->whereIn('id', $sortedQuestionsID)->all();
Everything works great and it both returns an array, checked it using dd(); then, I return it as a json
return response()->json([
'message' => 'Question loaded',
'sortedQuestions' => $sortedQuestions,
'questions' => $bankedQuestions,
'sortedIDs' => $sortedQuestionsID,
]);
THEN the confusing part comes into place. When I check the axios response the data types are very very different.
Any idea why this is happening guys? I've been checking the data and the parameters and everything are as expected. I'm using vueJS with Axios and Laravel.
Raw response:

Converting JSON to Doctrine Entity in Symfony

I'm currently working on building an API with the Symfony framwork. I've done enough reading to know to use the Serialization component, and built some custom normalizers for my entities. The way it currently works is:
JSON -> Array(Decode) -> User Entity(Denormalize)
This was working find as long as the request content was a JSON representation of the user, example:
{
"email": "demouser#email.com",
"plainPassword": "demouser",
"first_name" : "Demo",
"last_name" : "User"
}
A user entity is created using the following code in my controller:
$newuser = $this->get('api.serializer.default')->deserialize($request->getContent(), WebsiteUser::class, 'json');
However, I'd like to nest the user JSON in the 'data' property of a JSON object, which will allow consumers to pass additional metadata with the request, example:
{
"options": [
{
"foo": "bar"
}
],
"data": [
{
"email": "demouser#email.com",
"plainPassword": "demouser",
"first_name": "Demo",
"last_name": "User"
}
]
}
The main issue this causes is that the deserialization does not succeed because the JSON format has changed.
The only solution I've considered so far is to json_decode the whole request body, grab the 'data' element of that array, and pass the contents of the data element to the denormalizer (instead of the deserializer).
Is there a better way to solve this problem?
You should be able to get a specific key of your request body like follows:
$newuser = $this->get('api.serializer.default')->deserialize(
$request->request->get('data'), WebsiteUser::class, 'json'
);
If you are not able to retrieve the data from key without decoding your request body, look at this bundle, it consists in only one EventListener that replaces the request body after decode it.
You can easily integrate the same logic in your application, or requiring the bundle directly (which works well).

Best Practices and how to find get POST data from iOS AFNetworking in Symfony2 and return JSON in GET?

I am building a mobile app (iOS) and Symfony2 REST backend. On Symfony2, my routes are working correctly and I have tested them with AJAX and httpie, all CRUD operations, etc are fine. Now, I am trying to access the routes from the app. So far, I can access the routes and when I look into the Symfony2 Profiler, I can see entries in last 10 entries to verify that I am hitting the server with my POST and GET requests. Now, I have 2 questions and I would be glad if people can point me in the direction for ** Best Practices ** on how to proceed.
Problem 1: Although I am posting data which I can see coming in under "Request", when I try to create a record, it creates only NULL records, meaning the data is being lost. This is my controller for creating users for example:
public function postUserAction(Request $request)
{
$content = $this->get('request')->getContent();
$serializer = $this->get('jms_serializer');
$entity = $serializer->deserialize($content, 'Name\BundleName\Entity\User', 'json');
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return array(
'entity' => $entity,
);
}
When I look into the log, the only things that stand out are: Request Cookies (No cookies), Request Content: "Request content not available (it was retrieved as a resource)." This tells me the data was missing, how can I get this data and use it? Or what else could it be?
Problem 2: GET returns an empty JSON response with no data just the keys when I NSlog (echo it). My code looks like:
public function getUsersAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('NameBundle:User')->findAll();
return array(
'entities' => $entities,
);
}
From the log, it has the Request Cookies set: PHPSESSID => "1udududjjs83883jdlb4ho0j4" but again the Request Content says: "Request content not available (it was retrieved as a resource)." How can I make it return the data with the JSON? This works well in the browser AJAX and httpie tests.
Problem 3: Using AFNetworking, I have a symbolic constant which I set as the APIHost (IP Address) and APIPath was the folder. Now in my earlier version using native PHP, I constructed the actual code to be executed in index.php by sending the parameter in JSON so if I wanted a login, I sent something like todo:login but with Symfony2, I am not sure or know even the best practices for this case. Ideally, I would like to specify the server-side request in the JSON request and then find the correct route in Symfony2 but is this how to do it and if yes, can you please provide an example? The workaround is to specify hard coded paths in AFNetworking each time I need to make a request which I think tightly couples the code and I need to make changes in a lot of places anytime something changes on the server side. Thanks and sorry for the long question!
You expect the jmsserializer to do magic for you. But it won't, you have to configure it first. From you code I can see that you are using jmsserializer wrong.
In getUsersAction() you have to return a serialized response, but you are returning an array of objects. This would be the right way:
public function getUsersAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('NameBundle:User')->findAll();
$serializer = $container->get('jms_serializer');
return array(
'users' => $jsonContent = $serializer->serialize($entities, 'json');,
);
}
Your post action basically looks ok, however when the json does not contain every field of entity USER the deserialization will fail. You can configure the entity for serialization/deserialization using annotations.
http://jmsyst.com/libs/serializer/master/reference/annotations
I am not sure if I understood your last problem, but I think you have to hardcode the path in your app.
Symfony2 is great and absolutely useful when writing an API. But if you don't want to deal with serialization/deserialization you can give http://laravel.com/ a try. It is build on symfony and you can generate an api on the fly.

Categories