Skip to content
This repository was archived by the owner on Feb 25, 2022. It is now read-only.
Open
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
1 change: 1 addition & 0 deletions apistar/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# flake8: noqa
"""
_ ____ ___ ____ _
__/\__ / \ | _ \_ _| / ___|| |_ __ _ _ __ __/\__
Expand Down
42 changes: 21 additions & 21 deletions apistar/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@

class Document:
def __init__(self,
content: typing.Sequence[typing.Union['Section', 'Link']]=None,
url: str='',
title: str='',
description: str='',
version: str=''):
content: typing.Sequence[typing.Union['Section', 'Link']] = None,
url: str = '',
title: str = '',
description: str = '',
version: str = ''):
content = [] if (content is None) else list(content)

# Ensure all names within a document are unique.
Expand Down Expand Up @@ -55,9 +55,9 @@ def walk_links(self):
class Section:
def __init__(self,
name: str,
content: typing.Sequence[typing.Union['Section', 'Link']]=None,
title: str='',
description: str=''):
content: typing.Sequence[typing.Union['Section', 'Link']] = None,
title: str = '',
description: str = ''):
content = [] if (content is None) else list(content)

# Ensure all names within a section are unique.
Expand Down Expand Up @@ -104,13 +104,13 @@ class Link:
def __init__(self,
url: str,
method: str,
handler: typing.Callable=None,
name: str='',
encoding: str='',
response: 'Response'=None,
title: str='',
description: str='',
fields: typing.Sequence['Field']=None):
handler: typing.Callable = None,
name: str = '',
encoding: str = '',
response: 'Response' = None,
title: str = '',
description: str = '',
fields: typing.Sequence['Field'] = None):
method = method.upper()
fields = [] if (fields is None) else list(fields)

Expand Down Expand Up @@ -173,11 +173,11 @@ class Field:
def __init__(self,
name: str,
location: str,
title: str='',
description: str='',
required: bool=None,
schema: Validator=None,
example: typing.Any=None):
title: str = '',
description: str = '',
required: bool = None,
schema: Validator = None,
example: typing.Any = None):
assert location in ('path', 'query', 'body', 'cookie', 'header', 'formData')
if required is None:
required = True if location in ('path', 'body') else False
Expand All @@ -194,7 +194,7 @@ def __init__(self,


class Response:
def __init__(self, encoding: str, status_code: int=200, schema: Validator=None):
def __init__(self, encoding: str, status_code: int = 200, schema: Validator = None):
self.encoding = encoding
self.status_code = status_code
self.schema = schema
54 changes: 38 additions & 16 deletions apistar/schemas/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from apistar.compat import dict_type
from apistar.document import Document, Field, Link, Section
from apistar.schemas.jsonschema import JSON_SCHEMA, JSONSchema
from apistar.validators import Validator

SCHEMA_REF = validators.Object(
properties={'$ref': validators.String(pattern='^#/components/schemas/')}
Expand All @@ -15,6 +16,9 @@
RESPONSE_REF = validators.Object(
properties={'$ref': validators.String(pattern='^#/components/responses/')}
)
PARAMETERS_REF = validators.Object(
properties={'$ref': validators.String(pattern='^#/components/parameters/')}
)

OPEN_API = validators.Object(
def_name='OpenAPI',
Expand Down Expand Up @@ -116,7 +120,7 @@
('patch', validators.Ref('Operation')),
('trace', validators.Ref('Operation')),
('servers', validators.Array(items=validators.Ref('Server'))),
('parameters', validators.Array(items=validators.Ref('Parameter'))), # TODO: | ReferenceObject
('parameters', validators.Array(items=validators.Ref('Parameter') | PARAMETERS_REF)),
],
pattern_properties={
'^x-': validators.Any(),
Expand All @@ -130,7 +134,7 @@
('description', validators.String(format='textarea')),
('externalDocs', validators.Ref('ExternalDocumentation')),
('operationId', validators.String()),
('parameters', validators.Array(items=validators.Ref('Parameter'))), # TODO: | ReferenceObject
('parameters', validators.Array(items=validators.Ref('Parameter') | PARAMETERS_REF)),
('requestBody', REQUESTBODY_REF | validators.Ref('RequestBody')), # TODO: RequestBody | ReferenceObject
('responses', validators.Ref('Responses')),
# TODO: 'callbacks'
Expand Down Expand Up @@ -314,7 +318,8 @@ def load(self, data):
version = lookup(data, ['info', 'version'])
base_url = lookup(data, ['servers', 0, 'url'])
schema_definitions = self.get_schema_definitions(data)
content = self.get_content(data, base_url, schema_definitions)
parameter_definitions = self.get_parameter_definitions(data, schema_definitions)
content = self.get_content(data, base_url, schema_definitions, parameter_definitions)

return Document(title=title, description=description, version=version, url=base_url, content=content)

Expand All @@ -326,7 +331,26 @@ def get_schema_definitions(self, data):
definitions[key].def_name = key
return definitions

def get_content(self, data, base_url, schema_definitions):
def get_validator(self, schema, schema_definitions):
if schema is None or isinstance(schema, Validator):
return schema

if '$ref' in schema:
ref = schema['$ref'][len('#/components/schemas/'):]
return schema_definitions.get(ref)
else:
return JSONSchema().decode_from_data_structure(schema)

def get_parameter_definitions(self, data, schema_definitions):
definitions = {}
parameters = lookup(data, ['components', 'parameters'], {})
for key, value in parameters.items():
value["schema"] = self.get_validator(value.get("schema"), schema_definitions)
value["schema"].def_name = key
definitions[key] = value
return definitions

def get_content(self, data, base_url, schema_definitions, parameter_definitions):
"""
Return all the links in the document, layed out by tag and operationId.
"""
Expand All @@ -340,7 +364,8 @@ def get_content(self, data, base_url, schema_definitions):
}
for operation, operation_info in operations.items():
tag = lookup(operation_info, ['tags', 0])
link = self.get_link(base_url, path, path_info, operation, operation_info, schema_definitions)
link = self.get_link(
base_url, path, path_info, operation, operation_info, schema_definitions, parameter_definitions)
if link is None:
continue

Expand All @@ -357,7 +382,7 @@ def get_content(self, data, base_url, schema_definitions):
]
return links + sections

def get_link(self, base_url, path, path_info, operation, operation_info, schema_definitions):
def get_link(self, base_url, path, path_info, operation, operation_info, schema_definitions, parameter_definitions):
"""
Return a single link in the document.
"""
Expand All @@ -379,7 +404,7 @@ def get_link(self, base_url, path, path_info, operation, operation_info, schema_
parameters += operation_info.get('parameters', [])

fields = [
self.get_field(parameter, schema_definitions)
self.get_field(parameter, schema_definitions, parameter_definitions)
for parameter in parameters
]

Expand Down Expand Up @@ -409,24 +434,21 @@ def get_link(self, base_url, path, path_info, operation, operation_info, schema_
encoding=encoding
)

def get_field(self, parameter, schema_definitions):
def get_field(self, parameter, schema_definitions, parameter_definitions):
"""
Return a single field in a link.
"""
if '$ref' in parameter:
ref = parameter['$ref'][len('#/components/parameters/'):]
parameter = parameter_definitions.get(ref)

name = parameter.get('name')
location = parameter.get('in')
description = parameter.get('description')
required = parameter.get('required', False)
schema = parameter.get('schema')
schema = self.get_validator(parameter.get('schema'), schema_definitions)
example = parameter.get('example')

if schema is not None:
if '$ref' in schema:
ref = schema['$ref'][len('#/components/schemas/'):]
schema = schema_definitions.get(ref)
else:
schema = JSONSchema().decode_from_data_structure(schema)

return Field(
name=name,
location=location,
Expand Down
2 changes: 1 addition & 1 deletion apistar/tokenize/tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def __init__(self, value, start_index: int, end_index: int, content=None):
self._content = content

def get_value(self):
raise NotImplemented() # pragma: nocover
raise NotImplementedError() # pragma: nocover

@property
def start(self):
Expand Down
52 changes: 52 additions & 0 deletions testcases/openapi/parameters-example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
openapi: 3.0.2
info:
title: Parameters Example
version: 1.0.0
paths:
/parameters:
get:
operationId: getParameters
parameters:
- $ref: '#/components/parameters/Simple'
- $ref: '#/components/parameters/SimpleSchemaReference'
- name: inline
in: query
description: 'Query parameter defined inline'
required: false
schema:
type: string
- name: inline_schema_reference
in: query
description: 'Query parameter defined inline but with referenced schema'
required: false
schema:
$ref: '#/components/schemas/SchemaReference'
responses:
'200':
description: success
content:
application/json:
schema:
type: object
properties:
status:
type: string
components:
parameters:
Simple:
name: simple
in: query
description: 'Simple query parameters defined as component'
required: false
schema:
type: string
SimpleSchemaReference:
name: simple_schema_reference
in: query
description: 'Simple query parameters defined as component with schema referenced'
required: false
schema:
$ref: '#/components/schemas/SchemaReference'
schemas:
SchemaReference:
type: string
3 changes: 2 additions & 1 deletion tests/client/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@


@app.route('/path-param/{value}')
def path_param(request, value):
def path_param(request):
value = request.path_params['value']
return JSONResponse({'value': value})


Expand Down
1 change: 1 addition & 0 deletions tests/schemas/test_openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# 'testcases/openapi/callback-example.yaml',
# 'testcases/openapi/link-example.yaml',
'testcases/openapi/petstore-expanded.yaml',
'testcases/openapi/parameters-example.yaml',
'testcases/openapi/petstore.yaml',
'testcases/openapi/uspto.yaml',
]
Expand Down