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

Schema validation and error detail settings by get params #150

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) princip
* Support for semantic versioning api.
* [BC] DefaultHandler response code 404 instead 400
* [BC] Added Container to API Decider
* [BC] Output Configurator, Allows different methods for output configuration. Needs to be added to config services.

#### Added
* CorsPreflightHandlerInterface - resolve multiple service registered handler error
* Lazy API handlers

#### Added
* Button to copy `Body` content in api console
* Ability to disable schema validation and provide additional error info with get parameters.

#### Changed
* Handler tag wrapper has changed class from `btn` to `label`
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ application:
Api: Tomaj\NetteApi\Presenters\*Presenter
```

Then register your preffered output configurator in *config.neon* services:

```neon
services:
apiOutputConfigurator: Tomaj\NetteApi\Output\Configurator\DebuggerConfigurator
```

And add route to you RouterFactory:

```php
Expand Down
14 changes: 14 additions & 0 deletions src/Output/Configurator/ConfiguratorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Tomaj\NetteApi\Output\Configurator;

use Nette\Application\Request;

interface ConfiguratorInterface
{
public function validateSchema(?Request $request = null): bool;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ten request je v interface-y len kvoli tomu QueryConfiguratoru? nebolo by lepsie dat Http\Request do konstruktoru QueryConfiguratoru a ostatne implementacie nechat bez parametrov?


public function showErrorDetail(?Request $request = null): bool;
}
21 changes: 21 additions & 0 deletions src/Output/Configurator/DebuggerConfigurator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Tomaj\NetteApi\Output\Configurator;

use Nette\Application\Request;
use Tracy\Debugger;

class DebuggerConfigurator implements ConfiguratorInterface
{
public function validateSchema(?Request $request = null): bool
{
return !Debugger::$productionMode;
}

public function showErrorDetail(?Request $request = null): bool
{
return !Debugger::$productionMode;
}
}
41 changes: 41 additions & 0 deletions src/Output/Configurator/EnvConfigurator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Tomaj\NetteApi\Output\Configurator;

use Nette\Application\Request;

class EnvConfigurator implements ConfiguratorInterface
{
private $envVariable = 'APP_ENV';
private $productionValue = 'production';

/**
* @param string $envVariable Which environment variable to check for production value
* @param string $productionValue Value that indicates production environment eg. 'production' or 'prod'...
*/
public function __construct(string $envVariable = 'APP_ENV', string $productionValue = 'production')
{
$this->envVariable = $envVariable;
$this->productionValue = $productionValue;
}

public function validateSchema(?Request $request = null): bool
{
$appEnv = getenv($this->envVariable);
if ($appEnv === $this->productionValue) {
return false;
}
return true;
}

public function showErrorDetail(?Request $request = null): bool
{
$appEnv = getenv($this->envVariable);
if ($appEnv === $this->productionValue) {
return false;
}
return true;
}
}
41 changes: 41 additions & 0 deletions src/Output/Configurator/QueryConfigurator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Tomaj\NetteApi\Output\Configurator;

use Nette\Application\Request;

class QueryConfigurator implements ConfiguratorInterface
{
private $noSchemaValidateParam = 'no_schema_validate';
private $errorDetailParam = 'error_detail';

/**
* @param string $noSchemaValidateParam Name of get parameter to disable schema validation
* @param string $errorDetailParam Name of get parameter to show additional info in error response
*/
public function __construct(string $noSchemaValidateParam = 'no_schema_validate', string $errorDetailParam = 'error_detail')
{
$this->noSchemaValidateParam = $noSchemaValidateParam;
$this->errorDetailParam = $errorDetailParam;
}

public function validateSchema(?Request $request = null): bool
{
if ($request === null) {
return false;
}
$getParams = $request->getParameters();
return !isset($getParams[$this->noSchemaValidateParam]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

takze ?no_schema_validate=1 bude to iste ako ? no_schema_validate=0 hej? je to tak chcene?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skor som to chcel tak ze ?no_schema_validate&.... tiez vypne. Ale hej tympadom aj 0.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok sak ked si to tak chcel tak bude :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

az teraz som si uvedomil ze to chceme asi naopak skor - defaultne vypnute a s debugom zapnut - rovnako ako je to pri tom DebuggerConfiguratore

}

public function showErrorDetail(?Request $request = null): bool
{
if ($request === null) {
return false;
}
$getParams = $request->getParameters();
return isset($getParams[$this->errorDetailParam]);
}
}
11 changes: 8 additions & 3 deletions src/Presenters/ApiPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Tomaj\NetteApi\RateLimit\RateLimitInterface;
use Tomaj\NetteApi\Response\JsonApiResponse;
use Tracy\Debugger;
use Tomaj\NetteApi\Output\Configurator\ConfiguratorInterface;

final class ApiPresenter implements IPresenter
{
Expand All @@ -33,6 +34,9 @@ final class ApiPresenter implements IPresenter
/** @var Container @inject */
public $context;

/** @var ConfiguratorInterface @inject */
public $outputConfigurator;

/**
* CORS header settings
*
Expand Down Expand Up @@ -83,7 +87,7 @@ public function run(Request $request): IResponse
$paramsProcessor = new ParamsProcessor($handler->params());
if ($paramsProcessor->isError()) {
$this->response->setCode(Response::S400_BAD_REQUEST);
if (!Debugger::$productionMode) {
if ($this->outputConfigurator->showErrorDetail($request)) {
$response = new JsonResponse(['status' => 'error', 'message' => 'wrong input', 'detail' => $paramsProcessor->getErrors()]);
} else {
$response = new JsonResponse(['status' => 'error', 'message' => 'wrong input']);
Expand All @@ -94,7 +98,8 @@ public function run(Request $request): IResponse
try {
$response = $handler->handle($params);
$code = $response->getCode();
if (!Debugger::$productionMode) { /// If not production mode, validate output

if ($this->outputConfigurator->validateSchema($request)) {
$outputValid = count($handler->outputs()) === 0; // back compatibility for handlers with no outputs defined
$outputValidatorErrors = [];
foreach ($handler->outputs() as $output) {
Expand All @@ -115,7 +120,7 @@ public function run(Request $request): IResponse
}
}
} catch (Throwable $exception) {
if (!Debugger::$productionMode) {
if ($this->outputConfigurator->showErrorDetail($request)) {
$response = new JsonApiResponse(Response::S500_INTERNAL_SERVER_ERROR, ['status' => 'error', 'message' => 'Internal server error', 'detail' => $exception->getMessage()]);
} else {
$response = new JsonApiResponse(Response::S500_INTERNAL_SERVER_ERROR, ['status' => 'error', 'message' => 'Internal server error']);
Expand Down
9 changes: 6 additions & 3 deletions tests/Presenters/ApiPresenterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@

namespace Tomaj\NetteApi\Test\Presenters;

use PHPUnit\Framework\TestCase;
use Nette\Application\Request;
use Nette\DI\Container;
use Nette\Http\Response as HttpResponse;
use Nette\Http\Request as HttpRequest;
use Nette\Http\UrlScript;
use PHPUnit\Framework\TestCase;
use Tomaj\NetteApi\ApiDecider;
use Tomaj\NetteApi\Authorization\BearerTokenAuthorization;
use Tomaj\NetteApi\Authorization\NoAuthorization;
Expand All @@ -18,6 +16,7 @@
use Tomaj\NetteApi\Handlers\EchoHandler;
use Tomaj\NetteApi\Misc\IpDetector;
use Tomaj\NetteApi\Misc\StaticTokenRepository;
use Tomaj\NetteApi\Output\Configurator\DebuggerConfigurator;
use Tomaj\NetteApi\Presenters\ApiPresenter;
use Tomaj\NetteApi\Test\Handler\TestHandler;
use Tracy\Debugger;
Expand All @@ -41,6 +40,7 @@ public function testSimpleResponse()
$presenter->apiDecider = $apiDecider;
$presenter->response = new HttpResponse();
$presenter->context = new Container();
$presenter->outputConfigurator = new DebuggerConfigurator();

$request = new Request('Api:Api:default', 'GET', ['version' => '1', 'package' => 'test', 'apiAction' => 'api']);
$result = $presenter->run($request);
Expand All @@ -64,6 +64,7 @@ public function testWithAuthorization()
$presenter->apiDecider = $apiDecider;
$presenter->response = new HttpResponse();
$presenter->context = new Container();
$presenter->outputConfigurator = new DebuggerConfigurator();

$request = new Request('Api:Api:default', 'GET', ['version' => '1', 'package' => 'test', 'apiAction' => 'api']);
$result = $presenter->run($request);
Expand All @@ -85,6 +86,7 @@ public function testWithParams()
$presenter->apiDecider = $apiDecider;
$presenter->response = new HttpResponse();
$presenter->context = new Container();
$presenter->outputConfigurator = new DebuggerConfigurator();

Debugger::$productionMode = Debugger::PRODUCTION;

Expand Down Expand Up @@ -114,6 +116,7 @@ public function testWithOutputs()
$presenter->apiDecider = $apiDecider;
$presenter->response = new HttpResponse();
$presenter->context = new Container();
$presenter->outputConfigurator = new DebuggerConfigurator();

$request = new Request('Api:Api:default', 'GET', ['version' => '1', 'package' => 'test', 'apiAction' => 'api']);
$result = $presenter->run($request);
Expand Down
Loading