forked from loafle/openapi-generator-original
[php-slim4] Add Mock Server (#12044)
* Setup Data Mocker as dev dependency New 1.2.0 version of the package contains required factory class. * Refresh samples
This commit is contained in:
@@ -115,6 +115,22 @@ Switch your app environment to development in `public/.htaccess` file:
|
||||
</IfModule>
|
||||
```
|
||||
|
||||
## Mock Server
|
||||
Since this feature should be used for development only, change environment to `development` and send additional HTTP header `X-{{invokerPackage}}-Mock: ping` with any request to get mocked response.
|
||||
CURL example:
|
||||
```console
|
||||
curl --request GET \
|
||||
--url 'http://localhost:8888/v2/pet/findByStatus?status=available' \
|
||||
--header 'accept: application/json' \
|
||||
--header 'X-{{invokerPackage}}-Mock: ping'
|
||||
[{"id":-8738629417578509312,"category":{"id":-4162503862215270400,"name":"Lorem ipsum dol"},"name":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem i","photoUrls":["Lor"],"tags":[{"id":-3506202845849391104,"name":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectet"}],"status":"pending"}]
|
||||
```
|
||||
|
||||
Used packages:
|
||||
* [Openapi Data Mocker](https://github.com/ybelenko/openapi-data-mocker) - first implementation of OAS3 fake data generator.
|
||||
* [Openapi Data Mocker Server Middleware](https://github.com/ybelenko/openapi-data-mocker-server-middleware) - PSR-15 HTTP server middleware.
|
||||
* [Openapi Data Mocker Interfaces](https://github.com/ybelenko/openapi-data-mocker-interfaces) - package with mocking interfaces.
|
||||
|
||||
{{#generateApiDocs}}
|
||||
## API Endpoints
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"slim/psr7": "^1.1.0",
|
||||
{{/isSlimPsr7}}
|
||||
"ybelenko/openapi-data-mocker": "^1.0",
|
||||
"ybelenko/openapi-data-mocker-server-middleware": "^1.0"
|
||||
"ybelenko/openapi-data-mocker-server-middleware": "^1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"overtrue/phplint": "^2.0.2",
|
||||
|
||||
@@ -62,4 +62,37 @@ return [
|
||||
'pdo.options' => [
|
||||
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
||||
],
|
||||
|
||||
// mocker
|
||||
// OBVIOUSLY MUST NOT BE USED for production
|
||||
// @see https://github.com/ybelenko/openapi-data-mocker-server-middleware
|
||||
'mocker.getMockStatusCodeCallback' => function () {
|
||||
return function (\Psr\Http\Message\ServerRequestInterface $request, array $responses) {
|
||||
// check if client clearly asks for mocked response
|
||||
$pingHeader = 'X-{{invokerPackage}}-Mock';
|
||||
$pingHeaderCode = 'X-{{invokerPackage}}-Mock-Code';
|
||||
if (
|
||||
$request->hasHeader($pingHeader)
|
||||
&& $request->getHeader($pingHeader)[0] === 'ping'
|
||||
) {
|
||||
$responses = (array) $responses;
|
||||
$requestedResponseCode = ($request->hasHeader($pingHeaderCode)) ? $request->getHeader($pingHeaderCode)[0] : 'default';
|
||||
if (array_key_exists($requestedResponseCode, $responses)) {
|
||||
return $requestedResponseCode;
|
||||
}
|
||||
|
||||
// return first response key
|
||||
reset($responses);
|
||||
return key($responses);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
},
|
||||
'mocker.afterCallback' => function () {
|
||||
return function (\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response) {
|
||||
// mark mocked response to distinguish real and fake responses
|
||||
return $response->withHeader('X-{{invokerPackage}}-Mock', 'pong');
|
||||
};
|
||||
},
|
||||
];
|
||||
|
||||
@@ -59,6 +59,15 @@ final class RegisterDependencies
|
||||
\DI\get('pdo.password'),
|
||||
\DI\get('pdo.options', null)
|
||||
),
|
||||
|
||||
// DataMocker
|
||||
// @see https://github.com/ybelenko/openapi-data-mocker-server-middleware
|
||||
\OpenAPIServer\Mock\OpenApiDataMockerInterface::class => \DI\create(\OpenAPIServer\Mock\OpenApiDataMocker::class)
|
||||
->method('setModelsNamespace', '{{modelPackage}}\\'),
|
||||
|
||||
\OpenAPIServer\Mock\OpenApiDataMockerRouteMiddlewareFactory::class => \DI\autowire()
|
||||
->constructorParameter('getMockStatusCodeCallback', \DI\get('mocker.getMockStatusCodeCallback'))
|
||||
->constructorParameter('afterCallback', \DI\get('mocker.afterCallback')),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,16 @@ class RegisterRoutes
|
||||
return $response;
|
||||
});
|
||||
|
||||
// create mock middleware factory
|
||||
/** @var \Psr\Container\ContainerInterface */
|
||||
$container = $app->getContainer();
|
||||
/** @var \OpenAPIServer\Mock\OpenApiDataMockerRouteMiddlewareFactory|null */
|
||||
$mockMiddlewareFactory = null;
|
||||
if ($container->has(\OpenAPIServer\Mock\OpenApiDataMockerRouteMiddlewareFactory::class)) {
|
||||
// I know, anti-pattern. Don't retrieve dependency directly from container
|
||||
$mockMiddlewareFactory = $container->get(\OpenAPIServer\Mock\OpenApiDataMockerRouteMiddlewareFactory::class);
|
||||
}
|
||||
|
||||
foreach ($this->operations as $operation) {
|
||||
$callback = function (ServerRequestInterface $request) use ($operation) {
|
||||
$message = "How about extending {$operation['classname']} by {$operation['apiPackage']}\\{$operation['userClassname']} class implementing {$operation['operationId']} as a {$operation['httpMethod']} method?";
|
||||
@@ -129,6 +139,13 @@ class RegisterRoutes
|
||||
$callback = ["\\{$operation['apiPackage']}\\{$operation['userClassname']}", $operation['operationId']];
|
||||
}
|
||||
|
||||
if ($mockMiddlewareFactory) {
|
||||
$mockSchemaResponses = array_map(function ($item) {
|
||||
return json_decode($item['jsonSchema'], true);
|
||||
}, $operation['responses']);
|
||||
$middlewares[] = $mockMiddlewareFactory->create($mockSchemaResponses);
|
||||
}
|
||||
|
||||
$route = $app->map(
|
||||
[$operation['httpMethod']],
|
||||
"{$operation['basePathWithoutHost']}{$operation['path']}",
|
||||
|
||||
@@ -98,6 +98,22 @@ Switch your app environment to development in `public/.htaccess` file:
|
||||
</IfModule>
|
||||
```
|
||||
|
||||
## Mock Server
|
||||
Since this feature should be used for development only, change environment to `development` and send additional HTTP header `X-OpenAPIServer-Mock: ping` with any request to get mocked response.
|
||||
CURL example:
|
||||
```console
|
||||
curl --request GET \
|
||||
--url 'http://localhost:8888/v2/pet/findByStatus?status=available' \
|
||||
--header 'accept: application/json' \
|
||||
--header 'X-OpenAPIServer-Mock: ping'
|
||||
[{"id":-8738629417578509312,"category":{"id":-4162503862215270400,"name":"Lorem ipsum dol"},"name":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem i","photoUrls":["Lor"],"tags":[{"id":-3506202845849391104,"name":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectet"}],"status":"pending"}]
|
||||
```
|
||||
|
||||
Used packages:
|
||||
* [Openapi Data Mocker](https://github.com/ybelenko/openapi-data-mocker) - first implementation of OAS3 fake data generator.
|
||||
* [Openapi Data Mocker Server Middleware](https://github.com/ybelenko/openapi-data-mocker-server-middleware) - PSR-15 HTTP server middleware.
|
||||
* [Openapi Data Mocker Interfaces](https://github.com/ybelenko/openapi-data-mocker-interfaces) - package with mocking interfaces.
|
||||
|
||||
## API Endpoints
|
||||
|
||||
All URIs are relative to *http://petstore.swagger.io/v2*
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"php-di/slim-bridge": "^3.2",
|
||||
"slim/psr7": "^1.1.0",
|
||||
"ybelenko/openapi-data-mocker": "^1.0",
|
||||
"ybelenko/openapi-data-mocker-server-middleware": "^1.0"
|
||||
"ybelenko/openapi-data-mocker-server-middleware": "^1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"overtrue/phplint": "^2.0.2",
|
||||
|
||||
@@ -62,4 +62,37 @@ return [
|
||||
'pdo.options' => [
|
||||
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
||||
],
|
||||
|
||||
// mocker
|
||||
// OBVIOUSLY MUST NOT BE USED for production
|
||||
// @see https://github.com/ybelenko/openapi-data-mocker-server-middleware
|
||||
'mocker.getMockStatusCodeCallback' => function () {
|
||||
return function (\Psr\Http\Message\ServerRequestInterface $request, array $responses) {
|
||||
// check if client clearly asks for mocked response
|
||||
$pingHeader = 'X-OpenAPIServer-Mock';
|
||||
$pingHeaderCode = 'X-OpenAPIServer-Mock-Code';
|
||||
if (
|
||||
$request->hasHeader($pingHeader)
|
||||
&& $request->getHeader($pingHeader)[0] === 'ping'
|
||||
) {
|
||||
$responses = (array) $responses;
|
||||
$requestedResponseCode = ($request->hasHeader($pingHeaderCode)) ? $request->getHeader($pingHeaderCode)[0] : 'default';
|
||||
if (array_key_exists($requestedResponseCode, $responses)) {
|
||||
return $requestedResponseCode;
|
||||
}
|
||||
|
||||
// return first response key
|
||||
reset($responses);
|
||||
return key($responses);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
},
|
||||
'mocker.afterCallback' => function () {
|
||||
return function (\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response) {
|
||||
// mark mocked response to distinguish real and fake responses
|
||||
return $response->withHeader('X-OpenAPIServer-Mock', 'pong');
|
||||
};
|
||||
},
|
||||
];
|
||||
|
||||
@@ -72,6 +72,15 @@ final class RegisterDependencies
|
||||
\DI\get('pdo.password'),
|
||||
\DI\get('pdo.options', null)
|
||||
),
|
||||
|
||||
// DataMocker
|
||||
// @see https://github.com/ybelenko/openapi-data-mocker-server-middleware
|
||||
\OpenAPIServer\Mock\OpenApiDataMockerInterface::class => \DI\create(\OpenAPIServer\Mock\OpenApiDataMocker::class)
|
||||
->method('setModelsNamespace', 'OpenAPIServer\Model\\'),
|
||||
|
||||
\OpenAPIServer\Mock\OpenApiDataMockerRouteMiddlewareFactory::class => \DI\autowire()
|
||||
->constructorParameter('getMockStatusCodeCallback', \DI\get('mocker.getMockStatusCodeCallback'))
|
||||
->constructorParameter('afterCallback', \DI\get('mocker.afterCallback')),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -845,6 +845,16 @@ class RegisterRoutes
|
||||
return $response;
|
||||
});
|
||||
|
||||
// create mock middleware factory
|
||||
/** @var \Psr\Container\ContainerInterface */
|
||||
$container = $app->getContainer();
|
||||
/** @var \OpenAPIServer\Mock\OpenApiDataMockerRouteMiddlewareFactory|null */
|
||||
$mockMiddlewareFactory = null;
|
||||
if ($container->has(\OpenAPIServer\Mock\OpenApiDataMockerRouteMiddlewareFactory::class)) {
|
||||
// I know, anti-pattern. Don't retrieve dependency directly from container
|
||||
$mockMiddlewareFactory = $container->get(\OpenAPIServer\Mock\OpenApiDataMockerRouteMiddlewareFactory::class);
|
||||
}
|
||||
|
||||
foreach ($this->operations as $operation) {
|
||||
$callback = function (ServerRequestInterface $request) use ($operation) {
|
||||
$message = "How about extending {$operation['classname']} by {$operation['apiPackage']}\\{$operation['userClassname']} class implementing {$operation['operationId']} as a {$operation['httpMethod']} method?";
|
||||
@@ -858,6 +868,13 @@ class RegisterRoutes
|
||||
$callback = ["\\{$operation['apiPackage']}\\{$operation['userClassname']}", $operation['operationId']];
|
||||
}
|
||||
|
||||
if ($mockMiddlewareFactory) {
|
||||
$mockSchemaResponses = array_map(function ($item) {
|
||||
return json_decode($item['jsonSchema'], true);
|
||||
}, $operation['responses']);
|
||||
$middlewares[] = $mockMiddlewareFactory->create($mockSchemaResponses);
|
||||
}
|
||||
|
||||
$route = $app->map(
|
||||
[$operation['httpMethod']],
|
||||
"{$operation['basePathWithoutHost']}{$operation['path']}",
|
||||
|
||||
Reference in New Issue
Block a user