Files
pygeoapi/pygeoapi/openapi.py
T
2018-04-01 22:06:30 -04:00

281 lines
8.6 KiB
Python

# =================================================================
#
# Authors: Tom Kralidis <tomkralidis@gmail.com>
#
# Copyright (c) 2018 Tom Kralidis
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================
import logging
import click
import yaml
LOGGER = logging.getLogger(__name__)
def get_oas_30(cfg):
"""
Generates an OpenAPI 3.0 Document
:param cfg: configuration object
:returns: OpenAPI definition YAML dict
"""
paths = {}
LOGGER.debug('setting up server info')
oas = {
'openapi': '3.0.1',
'tags': []
}
info = {
'title': cfg['metadata']['identification']['title'],
'description': cfg['metadata']['identification']['description'],
'x-keywords': cfg['metadata']['identification']['keywords'],
'termsOfService':
cfg['metadata']['identification']['terms_of_service'],
'contact': {
'name': cfg['metadata']['provider']['name'],
'url': cfg['metadata']['provider']['url'],
'email': cfg['metadata']['contact']['email']
},
'license': {
'name': cfg['metadata']['license']['name'],
'url': cfg['metadata']['license']['url']
},
'version': '3.0.1'
}
oas['info'] = info
oas['servers'] = [{
'url': cfg['server']['url'],
'description': cfg['metadata']['identification']['description']
}]
paths['/'] = {
'get': {
'summary': 'API',
'description': 'API',
'tags': ['server'],
'responses': {
200: {
'description': 'successful operation'
}
}
}
}
paths['/api'] = {
'get': {
'summary': 'This document',
'description': 'This document',
'tags': ['server'],
'responses': {
200: {
'description': 'successful operation'
}
}
}
}
paths['/conformance'] = {
'get': {
'summary': 'API conformance definition',
'description': 'API conformance definition',
'tags': ['server'],
'responses': {
200: {
'description': 'successful operation'
}
}
}
}
paths['/collections'] = {
'get': {
'summary': 'Feature Collections',
'descriptions': 'Feature Collections',
'tags': ['server'],
'responses': {
200: {
'description': 'successful operation'
}
}
}
}
oas['tags'].append({
'name': 'server',
'description': cfg['metadata']['identification']['description'],
'externalDocs': {
'description': 'information',
'url': cfg['metadata']['identification']['url']}
}
)
LOGGER.debug('setting up datasets')
for k, v in cfg['datasets'].items():
tag = {
'name': k,
'description': v['description'],
'externalDocs': {}
}
for link in v['links']:
if link['type'] == 'information':
tag['externalDocs']['description'] = link['type']
tag['externalDocs']['url'] = link['url']
break
oas['tags'].append(tag)
paths['/collections/{}'.format(k)] = {
'get': {
'summary': 'Get feature collection metadata'.format(v['title']), # noqa
'description': v['description'],
'tags': [k],
'responses': {
200: {
'description': 'successful operation'
},
400: {
'description': 'Invalid ID supplied'
},
404: {
'description': 'not found'
}
}
}
}
paths['/collections/{}/items'.format(k)] = {
'get': {
'summary': 'Get {} features'.format(v['title']),
'description': v['description'],
'tags': [k],
'parameters': [
{'$ref': '#/components/parameters/limit'}
],
'responses': {
200: {
'description': 'successful operation'
},
400: {
'description': 'Invalid ID supplied'
},
404: {
'description': 'not found'
}
}
}
}
paths['/collections/{}/items/{{id}}'.format(k)] = {
'get': {
'summary': 'Get {} feature by ID'.format(v['title']),
'description': v['description'],
'tags': [k],
'parameters': [
{'$ref': '#/components/parameters/id'}
],
'responses': {
200: {
'description': 'successful operation'
},
400: {
'description': 'Invalid ID supplied'
},
404: {
'description': 'not found'
}
}
}
}
oas['paths'] = paths
oas['components'] = {
'parameters': {
'id': {
'name': 'id',
'in': 'path',
'description': 'The id of a feature',
'required': True,
'type': 'string'
},
'limit': {
'name': 'limit',
'in': 'query',
'description': ('The optional limit parameter limits the',
' number of items that are presented in the',
' response document. Only items are counted',
' that are on the first level of the',
' collection in the response document. Nested',
' objects contained within the explicitly',
' requested items shall not be counted.',
' Minimum = 1. Maximum = 10000.',
' Default = {}.'.format(
cfg['server']['limit'])),
'required': False,
'schema': {
'type': 'integer',
'minimum': 1,
'maximum': 10000,
'default': cfg['server']['limit']
},
'style': 'form',
'explode': False
}
}
}
return oas
def get_oas(cfg, version='3.0'):
"""
Stub to generate OpenAPI Document
:param cfg: configuration object
:param version: version of OpenAPI (default 3.0)
:returns: OpenAPI definition YAML dict
"""
if version == '3.0':
return get_oas_30(cfg)
else:
raise RuntimeError('OpenAPI version not supported')
@click.command()
@click.pass_context
@click.option('--config', '-c', 'config_file', help='configuration file')
def generate_openapi_document(ctx, config_file):
"""Generate OpenAPI Document"""
if config_file is None:
raise click.ClickException('--config/-c required')
with open(config_file) as ff:
s = yaml.load(ff)
click.echo(yaml.dump(get_oas(s), default_flow_style=False))