Extend OpenApi spec
This commit is contained in:
@@ -1,9 +1,24 @@
|
||||
api_platform:
|
||||
title: Goteo API
|
||||
version: 1.0.0
|
||||
title: The v4 API
|
||||
version: 4.0.0
|
||||
show_webby: false
|
||||
collection:
|
||||
order: 'DESC'
|
||||
openapi:
|
||||
contact:
|
||||
name: Fundación Platoniq
|
||||
url: http://platoniq.net/contact/
|
||||
email: contacto@platoniq.net
|
||||
termsOfService:
|
||||
license:
|
||||
name: MIT
|
||||
url:
|
||||
swagger_ui_extra_configuration:
|
||||
filter: true
|
||||
formats:
|
||||
json: ['application/json']
|
||||
# jsonld: ['application/ld+json']
|
||||
jsonld: ['application/ld+json']
|
||||
csv: ['text/csv']
|
||||
docs_formats:
|
||||
html: ['text/html']
|
||||
json: ['application/json']
|
||||
@@ -18,5 +33,3 @@ api_platform:
|
||||
rfc_7807_compliant_errors: true
|
||||
event_listeners_backward_compatibility_layer: false
|
||||
keep_legacy_inflector: false
|
||||
enable_re_doc: false
|
||||
show_webby: false
|
||||
|
||||
@@ -24,6 +24,12 @@ services:
|
||||
- '../src/Entity/'
|
||||
- '../src/Kernel.php'
|
||||
|
||||
App\OpenApi\OpenApiFactory:
|
||||
autoconfigure: false
|
||||
decorates: 'api_platform.openapi.factory'
|
||||
arguments:
|
||||
- '@App\OpenApi\OpenApiFactory.inner'
|
||||
|
||||
App\Library\Economy\Currency\ExchangeLocator:
|
||||
arguments:
|
||||
- !tagged 'app.lib.economy.currency.exchange'
|
||||
|
||||
+42
-1
@@ -1,3 +1,44 @@
|
||||
body {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#formats {
|
||||
margin: 0;
|
||||
padding: 20px 40px;
|
||||
max-width: 100%;
|
||||
background-color: #088787;
|
||||
}
|
||||
|
||||
#formats .information-container {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-width: none;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#formats .information-container .info {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#formats .information-container .info p {
|
||||
color: #2c2c2c;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
#formats .information-container .info a {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul[role="menu"]+div {
|
||||
position: sticky !important;
|
||||
}
|
||||
|
||||
.hl-yellow {
|
||||
background-color: #EFE1A8;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #2BBBB7;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Introduction
|
||||
The v4 API is a multi-capable web API based on the [API Platform](https://api-platform.com/) framework, built to support the future generation of the [Goteo](https://goteo.org) crowdfunding platform, aiming to be it's new underlying engine.
|
||||
|
||||
v4 exposes a REST API with predictable and resource-oriented URLs, accepts request bodies (payloads) encoded in multiple open standard formats such as JSON, including [JSON-LD](https://json-ld.org/) and [Hydra](https://www.hydra-cg.com/), returns responses encoded in the same formats, and uses standard HTTP verbs and status codes.
|
||||
|
||||
This API is documented in the OpenApi initiative [Specification v3.1.0](https://spec.openapis.org/oas/v3.1.0), which allows v4 to be easily understood by API development suites, documentation generators and SDK generators for the convenience of developers and API users. Most of the spec is generated automatically as changes are introduced, but some additional content such as this introduction and other sections might not be updated as regularly.
|
||||
|
||||
<span class="hl-yellow">
|
||||
This API is still in early development and is not set to have backward compatibility with the Goteo API v1 (http://api.goteo.org/v1/). Major changes are to be expected.
|
||||
</span>
|
||||
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace App\OpenApi;
|
||||
|
||||
use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface;
|
||||
use ApiPlatform\OpenApi\Model;
|
||||
use ApiPlatform\OpenApi\Model\Operation;
|
||||
use ApiPlatform\OpenApi\Model\PathItem;
|
||||
use ApiPlatform\OpenApi\Model\Paths;
|
||||
use ApiPlatform\OpenApi\OpenApi;
|
||||
|
||||
class OpenApiFactory implements OpenApiFactoryInterface
|
||||
{
|
||||
|
||||
public function __construct(private OpenApiFactoryInterface $decorated)
|
||||
{
|
||||
}
|
||||
|
||||
private function updateOperation(Operation $operation): Operation
|
||||
{
|
||||
$idParts = explode('_', $operation->getOperationId());
|
||||
$idResource = $operation->getTags()[0];
|
||||
$idOperation = array_slice($idParts, -1)[0];
|
||||
|
||||
switch ($idOperation) {
|
||||
case 'collection':
|
||||
$operationId = sprintf('List all %ss', $idResource);
|
||||
break;
|
||||
case 'post':
|
||||
$operationId = sprintf('Create one %s', $idResource);
|
||||
break;
|
||||
case 'get':
|
||||
$operationId = sprintf('Retrieve one %s', $idResource);
|
||||
break;
|
||||
case 'put':
|
||||
$operationId = sprintf('Update one %s', $idResource);
|
||||
break;
|
||||
case 'delete':
|
||||
$operationId = sprintf('Delete one %s', $idResource);
|
||||
break;
|
||||
case 'patch':
|
||||
$operationId = sprintf('Patch one %s', $idResource);
|
||||
break;
|
||||
default:
|
||||
$operationId = $operation->getOperationId();
|
||||
}
|
||||
|
||||
return $operation
|
||||
->withOperationId($operationId)
|
||||
->withSummary($operationId);
|
||||
}
|
||||
|
||||
private function updatePathItemOperations(PathItem $pathItem): PathItem
|
||||
{
|
||||
if ($pathItem->getGet()) {
|
||||
$pathItem = $pathItem->withGet(
|
||||
$this->updateOperation($pathItem->getGet())
|
||||
);
|
||||
}
|
||||
|
||||
if ($pathItem->getPost()) {
|
||||
$pathItem = $pathItem->withPost(
|
||||
$this->updateOperation($pathItem->getPost())
|
||||
);
|
||||
}
|
||||
|
||||
if ($pathItem->getPut()) {
|
||||
$pathItem = $pathItem->withPut(
|
||||
$this->updateOperation($pathItem->getPut())
|
||||
);
|
||||
}
|
||||
|
||||
if ($pathItem->getDelete()) {
|
||||
$pathItem = $pathItem->withDelete(
|
||||
$this->updateOperation($pathItem->getDelete())
|
||||
);
|
||||
}
|
||||
|
||||
if ($pathItem->getPatch()) {
|
||||
$pathItem = $pathItem->withPatch(
|
||||
$this->updateOperation($pathItem->getPatch())
|
||||
);
|
||||
}
|
||||
|
||||
return $pathItem;
|
||||
}
|
||||
|
||||
public function __invoke(array $context = []): OpenApi
|
||||
{
|
||||
$openApi = $this->decorated->__invoke($context);
|
||||
|
||||
$openApi = $openApi->withInfo(
|
||||
$openApi
|
||||
->getInfo()
|
||||
->withDescription(
|
||||
\file_get_contents(sprintf(
|
||||
'%s%s%s',
|
||||
__DIR__,
|
||||
DIRECTORY_SEPARATOR,
|
||||
'OpenApiDescription.md'
|
||||
))
|
||||
)
|
||||
);
|
||||
|
||||
$tags = [];
|
||||
foreach ($openApi->getComponents()->getSchemas() as $name => $schema) {
|
||||
if (\preg_match('/.*\.json/', $name)) continue;
|
||||
if (empty($schema['description'])) continue;
|
||||
|
||||
$tags[] = [
|
||||
'name' => $name,
|
||||
'description' => $schema['description']
|
||||
];
|
||||
}
|
||||
|
||||
$openApi = $openApi->withTags($tags);
|
||||
|
||||
$paths = new Paths();
|
||||
foreach ($openApi->getPaths()->getPaths() as $path => $pathItem) {
|
||||
$pathItem = $this->updatePathItemOperations($pathItem);
|
||||
|
||||
$paths->addPath($path, $pathItem);
|
||||
}
|
||||
|
||||
$openApi = $openApi->withPaths($paths);
|
||||
|
||||
$openApi = $openApi->withServers([
|
||||
new Model\Server(sprintf('%s://%s', $_SERVER['REQUEST_SCHEME'], $_SERVER['HTTP_HOST']))
|
||||
]);
|
||||
|
||||
return $openApi;
|
||||
}
|
||||
}
|
||||
@@ -1,87 +1,122 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
{% block head_metas %}
|
||||
<meta charset="UTF-8">
|
||||
<meta charset="UTF-8">
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>{% if title %}{{ title }}{% endif %}</title>
|
||||
<title>{{ title }}</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block stylesheet %}
|
||||
<link rel="stylesheet" href="{{ asset('bundles/apiplatform/fonts/open-sans/400.css', assetPackage) }}">
|
||||
<link rel="stylesheet" href="{{ asset('bundles/apiplatform/fonts/open-sans/700.css', assetPackage) }}">
|
||||
<link rel="stylesheet" href="{{ asset('bundles/apiplatform/swagger-ui/swagger-ui.css', assetPackage) }}">
|
||||
<link rel="stylesheet" href="{{ asset('bundles/apiplatform/style.css', assetPackage) }}">
|
||||
<link rel="stylesheet" href="{{ asset('style.css', assetPackage) }}">
|
||||
<link rel="stylesheet" href="{{ asset('bundles/apiplatform/fonts/open-sans/400.css', assetPackage) }}">
|
||||
<link rel="stylesheet" href="{{ asset('bundles/apiplatform/fonts/open-sans/700.css', assetPackage) }}">
|
||||
<link rel="stylesheet" href="{{ asset('bundles/apiplatform/swagger-ui/swagger-ui.css', assetPackage) }}">
|
||||
<link rel="stylesheet" href="{{ asset('bundles/apiplatform/style.css', assetPackage) }}">
|
||||
<link rel="stylesheet" href="{{ asset('style.css', assetPackage) }}">
|
||||
{% endblock %}
|
||||
|
||||
{% set oauth_data = {'oauth': swagger_data.oauth|merge({'redirectUrl' : absolute_url(asset('bundles/apiplatform/swagger-ui/oauth2-redirect.html', assetPackage)) })} %}
|
||||
{% set oauth_data = {'oauth': swagger_data.oauth|merge({'redirectUrl' :
|
||||
absolute_url(asset('bundles/apiplatform/swagger-ui/oauth2-redirect.html', assetPackage)) })} %}
|
||||
|
||||
{% block head_javascript %}
|
||||
{# json_encode(65) is for JSON_UNESCAPED_SLASHES|JSON_HEX_TAG to avoid JS XSS #}
|
||||
<script id="swagger-data" type="application/json">{{ swagger_data|merge(oauth_data)|json_encode(65)|raw }}</script>
|
||||
{# json_encode(65) is for JSON_UNESCAPED_SLASHES|JSON_HEX_TAG to avoid JS XSS #}
|
||||
<script id="swagger-data" type="application/json">{{ swagger_data|merge(oauth_data)|json_encode(65)|raw }}</script>
|
||||
{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="svg-icons">
|
||||
<defs>
|
||||
<symbol viewBox="0 0 20 20" id="unlocked">
|
||||
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
|
||||
</symbol>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="svg-icons">
|
||||
<defs>
|
||||
<symbol viewBox="0 0 20 20" id="unlocked">
|
||||
<path
|
||||
d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z">
|
||||
</path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="locked">
|
||||
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"></path>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 20 20" id="locked">
|
||||
<path
|
||||
d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z">
|
||||
</path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="close">
|
||||
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"></path>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 20 20" id="close">
|
||||
<path
|
||||
d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z">
|
||||
</path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="large-arrow">
|
||||
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"></path>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 20 20" id="large-arrow">
|
||||
<path
|
||||
d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z">
|
||||
</path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="large-arrow-down">
|
||||
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"></path>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 20 20" id="large-arrow-down">
|
||||
<path
|
||||
d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z">
|
||||
</path>
|
||||
</symbol>
|
||||
|
||||
|
||||
<symbol viewBox="0 0 24 24" id="jump-to">
|
||||
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"></path>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 24 24" id="jump-to">
|
||||
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"></path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 24 24" id="expand">
|
||||
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"></path>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 24 24" id="expand">
|
||||
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"></path>
|
||||
</symbol>
|
||||
|
||||
</defs>
|
||||
</svg>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
<div id="swagger-ui" class="api-platform"></div>
|
||||
<div id="swagger-ui" class="api-platform"></div>
|
||||
|
||||
<div class="swagger-ui" id="formats">
|
||||
<div class="information-container wrapper">
|
||||
<div class="info">
|
||||
Available formats:
|
||||
{% for format in formats|keys %}
|
||||
<a href="{{ path(originalRoute, originalRouteParams|merge({'_format': format})) }}">{{ format }}</a>
|
||||
{% endfor %}
|
||||
<br/>
|
||||
Built with:
|
||||
<a href="https://api-platform.com/" target="_blank">API Platform</a>
|
||||
<div class="swagger-ui" id="formats">
|
||||
<div class="information-container wrapper">
|
||||
<div class="info">
|
||||
<p>Available formats:</p>
|
||||
<p>
|
||||
{% for format in formats|keys %}
|
||||
<a href="{{ path(originalRoute, originalRouteParams|merge({'_format': format})) }}">{{ format }}</a>
|
||||
{% endfor %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<p>Other API docs:</p>
|
||||
<p>
|
||||
{% set active_ui = app.request.get('ui', 're_doc') %}
|
||||
{% if swaggerUiEnabled and active_ui != 'swagger_ui' %}
|
||||
<a href="{{ path('api_doc', {'ui': 'swagger_ui'}) }}">Swagger UI</a>
|
||||
{% endif %}
|
||||
{% if reDocEnabled and active_ui != 're_doc' %}
|
||||
<a href="{{ path('api_doc', {'ui': 're_doc'}) }}">ReDoc</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<p>Built with:</p>
|
||||
<p>
|
||||
<a href="https://api-platform.com/" target="_blank">API Platform</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block javascript %}
|
||||
{% block javascript %}
|
||||
{% if (swaggerUiEnabled and not reDocEnabled) or (swaggerUiEnabled and 'swagger_ui' == active_ui) %}
|
||||
<script src="{{ asset('bundles/apiplatform/swagger-ui/swagger-ui-bundle.js', assetPackage) }}"></script>
|
||||
<script src="{{ asset('bundles/apiplatform/swagger-ui/swagger-ui-standalone-preset.js', assetPackage) }}"></script>
|
||||
<script src="{{ asset('bundles/apiplatform/init-swagger-ui.js', assetPackage) }}"></script>
|
||||
{% else %}
|
||||
<script src="{{ asset('bundles/apiplatform/redoc/redoc.standalone.js', assetPackage) }}"></script>
|
||||
<script src="{{ asset('bundles/apiplatform/init-redoc-ui.js', assetPackage) }}"></script>
|
||||
{% endif %}
|
||||
<script src="{{ asset('bundles/apiplatform/init-common-ui.js', assetPackage) }}" defer></script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user