saloon icon indicating copy to clipboard operation
saloon copied to clipboard

Good place to add validations for requests?

Open abishekrsrikaanth opened this issue 3 years ago • 2 comments

What is a good place to add validations for requests before they are submitted? For example, a request requires atleast 2 values on an array passed to it. I want to add this validation before the request is submitted and throw an error. What would be a good place to do this?

abishekrsrikaanth avatar Aug 11 '22 19:08 abishekrsrikaanth

The best place is probably in the “boot” method of the request. That method is run right before the request is made.

Just extend the method from the base SaloonRequest class :)

Sammyjo20 avatar Aug 11 '22 21:08 Sammyjo20

Here is an example

class CreateForgeServerRequest extends SaloonRequest
{
    //...

    public function boot(): void
    {
        // $data = $this->getData();

        throw new ValidationException;
    }
}

Sammyjo20 avatar Aug 12 '22 04:08 Sammyjo20

Thank you. Appreciate the help. BTW, love the project.

abishekrsrikaanth avatar Aug 12 '22 10:08 abishekrsrikaanth

Hello @Sammyjo20

I know this issue is closed already but I thought is best to discuss here since my doubt is on the same topic.

I am building an SDK with Saloon and trying to validate the data. My approach at the moment is validating on the DTO model since I'm using it to both send the requests and receive the responses.

Since I plan on using this SDK on my projects (which mostly use Laravel) I thought it was best to use the Laravel validation, so I added the illuminate/validation package to my composer.json. My problem is that I can't use the facades outside Laravel, and to instantiate the Validator class manually I have to instantiate many more classes, which led me to think mabe is best to take on another validation package or leave the validation to the developer integrating with the SDK.

The first approach feels strange to me since Saloon awready works great with Laravel and uses some of its components, but I would like to offer a complete functional SDK with all validation, thus I don't feel comfortable with the second option either.

What would you suggest I do in this scenario? Is there a way to use the Validator facade within my package or the only option is to use another package?

guiiamorim avatar Oct 06 '22 13:10 guiiamorim

Hey @guiiamorim

Good question. When I build SDKs I typically assume it's the developer's responsibility to input good data to make it work, and my "validation" is minimal type checking. I like that you want to try and validate it, and if it were me I would try to install illuminate/validation.

You could try installing it using the following article?

https://dailydevsblog.com/troubleshoot/resolved-make-laravel-8s-validator-class-work-outside-the-framework-160285

I also found this: https://github.com/Respect/Validation or this https://github.com/rakit/validation

Hope that helps

Sammyjo20 avatar Oct 06 '22 17:10 Sammyjo20

Hi @Sammyjo20

Thank you for the help, I managed to use the validation from Laravel using the article you provided. It's kinda ugly, but since I don't expect other people to use my SDK it doesn't matter that much.

For people trying to do the same thing, I found a gotcha when trying to use Enum validation (I think it applies to all rules instantiated manually, but I didn't test), since it requires a helper function to retrieve the message, which is located in the illuminate/foundation (which I couldn't install). I'll post my code here for reference.

file helpers.php:

use Illuminate\Filesystem\Filesystem;
use Illuminate\Translation\FileLoader;
use Illuminate\Translation\Translator;

if (! function_exists('trans')) {
    /**
     * Translate the given message.
     *
     * @param string|null $key
     * @param array $replace
     * @param string|null $locale
     * @return Translator|string|array|null
     */
    function trans(string $key = null, array $replace = [], string $locale = null): array|string|Translator|null
    {
        if (! function_exists('resolve')) {
            $loader = new FileLoader(new Filesystem(), dirname(__FILE__, 2) . '/lang');
            $loader->addNamespace('lang', dirname(__FILE__, 2));
            $loader->load('en', 'validation', 'lang');
            $translator = new Translator($loader, 'en');
        }

        if (! isset($translator)) {
            $translator = resolve('translator');
        }

        if (is_null($key)) {
            return $translator;
        }

        return $translator->get($key, $replace, $locale);
    }
}

composer.json:

...
"autoload": {
    "psr-4": {
        "Asaas\\": "src/",
        "Asaas\\Tests\\": "tests/"
    },
    "files": [
        "src/helpers.php"
    ]
},
...

I also made a trait with a function to retrieve the validator, but you could also make a helper function

/**
* @return Factory
*/
private function createValidator(): Factory
{
  if (function_exists('resolve')) {
      return \resolve('validator');
  }

  return new Factory(
      trans()
  );
}

I didn't test the SDK in a laravel environment yet, so maybe some errors will arrive down the road, I'll keep this updated should I change something.

guiiamorim avatar Oct 07 '22 13:10 guiiamorim