add support for provider plugin schemas (#1022)
This commit is contained in:
@@ -94,6 +94,10 @@ The below template provides a minimal example (let's call the file ``mycoolvecto
|
||||
}]
|
||||
}
|
||||
|
||||
def get_schema():
|
||||
# return a `dict` of a JSON schema (inline or reference)
|
||||
return ('application/geo+json', {'$ref': 'https://geojson.org/schema/Feature.json'})
|
||||
|
||||
|
||||
For brevity, the above code will always return the single feature of the dataset. In reality, the plugin
|
||||
developer would connect to a data source with capabilities to run queries and return a relevant result set,
|
||||
|
||||
+2
-2
@@ -1920,7 +1920,7 @@ class API:
|
||||
LOGGER.debug('Creating item')
|
||||
try:
|
||||
identifier = p.create(request.data)
|
||||
except ProviderInvalidDataError as err:
|
||||
except (ProviderInvalidDataError, TypeError) as err:
|
||||
msg = str(err)
|
||||
return self.get_exception(
|
||||
400, headers, request.format, 'InvalidParameterValue', msg)
|
||||
@@ -1934,7 +1934,7 @@ class API:
|
||||
LOGGER.debug('Updating item')
|
||||
try:
|
||||
_ = p.update(identifier, request.data)
|
||||
except ProviderGenericError as err:
|
||||
except (ProviderInvalidDataError, TypeError) as err:
|
||||
msg = str(err)
|
||||
return self.get_exception(
|
||||
400, headers, request.format, 'InvalidParameterValue', msg)
|
||||
|
||||
+50
-18
@@ -39,7 +39,7 @@ import yaml
|
||||
from pygeoapi import __version__
|
||||
from pygeoapi import l10n
|
||||
from pygeoapi.plugin import load_plugin
|
||||
from pygeoapi.provider.base import ProviderTypeError
|
||||
from pygeoapi.provider.base import ProviderTypeError, SchemaType
|
||||
from pygeoapi.util import (filter_dict_by_key_value, get_provider_by_type,
|
||||
filter_providers_by_type, to_json, yaml_load)
|
||||
|
||||
@@ -523,19 +523,21 @@ def get_oas_30(cfg):
|
||||
|
||||
if p.editable:
|
||||
LOGGER.debug('Provider is editable; adding post')
|
||||
|
||||
paths[items_path]['post'] = {
|
||||
'summary': 'Add {} items'.format(title), # noqa
|
||||
'description': desc,
|
||||
'tags': [name],
|
||||
'operationId': 'add{}Features'.format(name.capitalize()),
|
||||
'consumes': ['application/json'],
|
||||
'produces': ['application/json'],
|
||||
'parameters': [{
|
||||
'in': 'body',
|
||||
'name': 'body',
|
||||
'requestBody': {
|
||||
'description': 'Adds item to collection',
|
||||
'required': True,
|
||||
}],
|
||||
'content': {
|
||||
'application/json': {
|
||||
'schema': {}
|
||||
}
|
||||
},
|
||||
'required': True
|
||||
},
|
||||
'responses': {
|
||||
'201': {'description': 'Successful creation'},
|
||||
'400': {'$ref': '{}#/components/responses/InvalidParameter'.format(OPENAPI_YAML['oapif'])}, # noqa
|
||||
@@ -543,6 +545,14 @@ def get_oas_30(cfg):
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
schema_ref = p.get_schema(SchemaType.create)
|
||||
paths[items_path]['post']['requestBody']['content'][schema_ref[0]] = { # noqa
|
||||
'schema': schema_ref[1]
|
||||
}
|
||||
except Exception as err:
|
||||
LOGGER.debug(err)
|
||||
|
||||
if ptype == 'record':
|
||||
paths[items_path]['get']['parameters'].append(
|
||||
{'$ref': '{}/parameters/q.yaml'.format(OPENAPI_YAML['oapir'])}) # noqa
|
||||
@@ -631,36 +641,58 @@ def get_oas_30(cfg):
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
schema_ref = p.get_schema()
|
||||
paths['{}/items/{{featureId}}'.format(collection_name_path)]['get']['responses']['200'] = { # noqa
|
||||
'content': {
|
||||
schema_ref[0]: {
|
||||
'schema': schema_ref[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
except Exception as err:
|
||||
LOGGER.debug(err)
|
||||
|
||||
if p.editable:
|
||||
LOGGER.debug('Provider is editable; adding put/delete')
|
||||
paths['{}/items/{{featureId}}'.format(collection_name_path)]['put'] = { # noqa
|
||||
put_path = '{}/items/{{featureId}}'.format(collection_name_path) # noqa
|
||||
paths[put_path]['put'] = { # noqa
|
||||
'summary': 'Update {} items'.format(title),
|
||||
'description': desc,
|
||||
'tags': [name],
|
||||
'operationId': 'update{}Features'.format(name.capitalize()), # noqa
|
||||
'consumes': ['application/json'],
|
||||
'produces': ['application/json'],
|
||||
'parameters': [
|
||||
{'$ref': '{}#/components/parameters/featureId'.format(OPENAPI_YAML['oapif'])}, # noqa
|
||||
{
|
||||
'in': 'body',
|
||||
'name': 'body',
|
||||
'description': 'Updates item in collection',
|
||||
'required': True,
|
||||
}
|
||||
],
|
||||
'requestBody': {
|
||||
'description': 'Updates item in collection',
|
||||
'content': {
|
||||
'application/json': {
|
||||
'schema': {}
|
||||
}
|
||||
},
|
||||
'required': True
|
||||
},
|
||||
'responses': {
|
||||
'204': {'description': 'Successful update'},
|
||||
'400': {'$ref': '{}#/components/responses/InvalidParameter'.format(OPENAPI_YAML['oapif'])}, # noqa
|
||||
'500': {'$ref': '{}#/components/responses/ServerError'.format(OPENAPI_YAML['oapif'])} # noqa
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
schema_ref = p.get_schema(SchemaType.replace)
|
||||
paths[put_path]['put']['requestBody']['content'][schema_ref[0]] = { # noqa
|
||||
'schema': schema_ref[1]
|
||||
}
|
||||
except Exception as err:
|
||||
LOGGER.debug(err)
|
||||
|
||||
paths['{}/items/{{featureId}}'.format(collection_name_path)]['delete'] = { # noqa
|
||||
'summary': 'Delete {} items'.format(title),
|
||||
'description': desc,
|
||||
'tags': [name],
|
||||
'operationId': 'delete{}Features'.format(name.capitalize()), # noqa
|
||||
'produces': ['application/json'],
|
||||
'parameters': [
|
||||
{'$ref': '{}#/components/parameters/featureId'.format(OPENAPI_YAML['oapif'])}, # noqa
|
||||
],
|
||||
|
||||
@@ -29,10 +29,18 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
from enum import Enum
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SchemaType(Enum):
|
||||
item = 'item'
|
||||
create = 'create'
|
||||
update = 'update'
|
||||
replace = 'replace'
|
||||
|
||||
|
||||
class BaseProvider:
|
||||
"""generic Provider ABC"""
|
||||
|
||||
@@ -79,6 +87,18 @@ class BaseProvider:
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_schema(self, schema_type: SchemaType = SchemaType.item):
|
||||
"""
|
||||
Get provider schema model
|
||||
|
||||
:param schema_type: `SchemaType` of schema (default is 'item')
|
||||
|
||||
:returns: tuple pair of `str` of media type and `dict` of schema
|
||||
(i.e. JSON Schema)
|
||||
"""
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_data_path(self, baseurl, urlpath, dirpath):
|
||||
"""
|
||||
Gets directory listing or file description or raw file dump
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Swagger UI - {{ config['metadata']['identification']['title'] }}</title>
|
||||
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@3.28.0/swagger-ui.css" >
|
||||
<link rel="icon" type="image/png" href="https://unpkg.com/swagger-ui-dist@3.28.0/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="https://unpkg.com/swagger-ui-dist@3.28.0/favicon-16x16.png" sizes="16x16" />
|
||||
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist/swagger-ui.css" >
|
||||
<link rel="icon" type="image/png" href="https://unpkg.com/swagger-ui-dist/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="https://unpkg.com/swagger-ui-dist/favicon-16x16.png" sizes="16x16" />
|
||||
<style>
|
||||
html
|
||||
{
|
||||
@@ -30,8 +30,8 @@
|
||||
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="https://unpkg.com/swagger-ui-dist@3.28.0/swagger-ui-bundle.js"> </script>
|
||||
<script src="https://unpkg.com/swagger-ui-dist@3.28.0/swagger-ui-standalone-preset.js"> </script>
|
||||
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"> </script>
|
||||
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js"> </script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
// Begin Swagger UI call region
|
||||
|
||||
Reference in New Issue
Block a user