Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate subkey #6

Closed
Lo5t opened this issue Aug 24, 2016 · 18 comments
Closed

Validate subkey #6

Lo5t opened this issue Aug 24, 2016 · 18 comments
Assignees
Milestone

Comments

@Lo5t
Copy link

Lo5t commented Aug 24, 2016

How can I validate sub keys

{"type":"emails", "objectid":"1", "email":{ "id":1, "enable_mapping":"1", "name":"rq3r", "created_at":"2016-08-23 13:36:29", "updated_at":"2016-08-23 14:36:47" } }

I would like to validate the email object.
If I understand correctly then its merely top level

$param = $request->getParam($key);

@DavidePastore
Copy link
Owner

Yes, you're right. Slim-Validation doesn't know about your json request, but we could add some kind of logic to also validate it. What do you think?

@Lo5t
Copy link
Author

Lo5t commented Aug 24, 2016

somethign like this
if (is_array($param) or ($param instanceof Traversable))
but would chuck the whole thing in a function make it self callable then it doesn't matter how deep the nesting goes.

@DavidePastore
Copy link
Owner

If you want you can prepare a PR ;)

@Lo5t
Copy link
Author

Lo5t commented Aug 24, 2016

will do :)

@Lo5t
Copy link
Author

Lo5t commented Aug 25, 2016

The problem is without knowing the dimension of the array traversing the elements becomes more expensive.
view suggestion below.

`
/**
* Validation middleware invokable class.
*
* @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
* @param \Psr\Http\Message\ResponseInterface $response PSR7 response
* @param callable $next Next middleware
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function __invoke($request, $response, $next)
{
$this->errors = [];

    //Validate every parameters in the validators array
    $parsedBody = $request->getParsedBody();
    foreach ($this->validators as $key => $validator) {
        recursiveLoop($parsedBody, $key, $validator)
    }

    return $next($request, $response);
}

/**
 * Recursive function to allow for Multidimensional arrays
 *
 * @param array    $parsedBody
 * @param String   $key
 * @param object   $validator
 */
private function recursiveLoop($parsedBody, $key, $validator){
    foreach ($parsedBody as $parsedObjectKey =>  $parsedObject) {
        if (is_array($parsedObject)){
            recursiveLoop($parsedObject, $key, $validator);
        }
        else{
            if($parsedObjectKey == $key){
                try {
                    $validator->assert($parsedObject);
                } catch (NestedValidationException $exception) {
                    if ($this->translator) {
                        $exception->setParam('translator', $this->translator);
                    }
                    $this->errors[$key] = $exception->getMessages();
                }
            }
        }
    }
}`

@DavidePastore
Copy link
Owner

Thanks for the suggestion @Lo5t . The problem with that snippet is that it won't work anymore with the old style (GET and POST parameters). I'm actually working on it and I'm trying to find a simpler solution that maybe could help you.

@DavidePastore DavidePastore added this to the next milestone Aug 26, 2016
@DavidePastore
Copy link
Owner

@Lo5t please check #7 and tell me what you think of it.

@DavidePastore
Copy link
Owner

@Lo5t ping

@achimha
Copy link

achimha commented Sep 25, 2016

It would be best to integrate json-schema for real JSON validation: https://github.com/justinrainbow/json-schema

A Slim middleware implementation is found here: https://github.com/moffe42/json-schema-middleware

One typically has both standard request parameters (query, form parameters in the body) and JSON in the body so it makes sense to merge both approaches into one.

I wouldn't bother doing some minimal JSON inspection, it will only marginally help and a more thorough solution is available as JSON Schema.

@DavidePastore
Copy link
Owner

Hi @achimha, thanks for your comment. I think that we could create another Validation class (named JsonSchemaValidation) to validate using this different style. I think that the old approach should still exist, so you can have two different choices. What do you think?

@achimha
Copy link

achimha commented Sep 26, 2016

I agree with JsonSchemaValidation. I personally wouldn't bother with an alternative approach other than "is valid JSON" because it is very restricted, not a generic solution and only of limited use in some situations.

I'd very much appreciate JSON Schema support!

@DavidePastore
Copy link
Owner

Ok nice, I'll see if I could create a solution in the next days. Anyway did you try the solution proposed here?

@achimha
Copy link

achimha commented Sep 26, 2016

Yes, I saw that. It's a lot of typing and it only covers very simple cases. You can have a lot of optional values, arrays with certain allowed sizes, etc.

Your example mentioned above uses a function injected into the container. I think that is a bit inflexible as you normally have many APIs with different parameters and I believe it would be beneficial to have a middleware that you parameterize for each request, something like this:

$this->post('/myroute', function(Request $request, Response $response)  {
    return $response
        ->withHeader('Content-Type', 'application/json')
        ->withStatus(myRequestHandler($request->getParsedBody(), $request->getQueryParams()));
})->add(new TheMiddleware({
   "validation" => "parameters",
   "defining" => "how to validate this route"
});

@DavidePastore
Copy link
Owner

@achimha Be free to create a PR for this 😄

@achimha
Copy link

achimha commented Sep 27, 2016

I didn't expect any other answer... I'm not using the library at this point, planning to find a solution in the next few weeks so I can't provide anything today.

Why did you go the way of injecting validation methods into the container instead of adding them as middleware? Any specific reason?

@DavidePastore
Copy link
Owner

The only reason that I could find is: ignorance. You're right about it, it should be something directly accessible in the $request or in the $response object. What do you think is the best approach?

@achimha
Copy link

achimha commented Sep 27, 2016

I believe the cleanest approach is to use what they call "invokable class middleware": http://www.slimframework.com/docs/concepts/middleware.html

You'd just do

$route->add(new ExampleMiddleware());

and parametrize it there. If there was a class representing JSON Schema, you would just define the schema in the constructor of that middleware and attach it to the route.

@DavidePastore
Copy link
Owner

Did you check the source code of Validation.php? You can see that it is already an "invokable class middleware". What you can't find in the documentation is how to improve the request/response object adding a validate method to it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants