Add the default value for the 'servers' array

The specification:

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oasObject

requires that if the 'servers' array is not provided or empty,
its default value is an array of a single Server Object
with 'url' of '/'.
This commit is contained in:
Peter Bašista 2018-02-15 15:28:15 +01:00
parent 821f14e84b
commit a0305fb97d
6 changed files with 92 additions and 7 deletions

View file

@ -41,6 +41,9 @@ class ServersGenerator(object):
def generate(self, servers_spec):
servers_deref = self.dereferencer.dereference(servers_spec)
if not servers_deref:
yield Server('/')
return
for server_spec in servers_deref:
url = server_spec['url']
variables_spec = server_spec.get('variables', {})
@ -65,9 +68,6 @@ class ServerVariablesGenerator(object):
def generate(self, variables_spec):
variables_deref = self.dereferencer.dereference(variables_spec)
if not variables_deref:
return
for variable_name, variable_spec in iteritems(variables_deref):
default = variable_spec['default']
enum = variable_spec.get('enum')

View file

@ -1,5 +1,6 @@
"""OpenAPI core validators module"""
from six import iteritems
from yarl import URL
from openapi_core.exceptions import (
OpenAPIMappingError, MissingParameter, MissingBody, InvalidResponse,
@ -51,6 +52,16 @@ class ResponseValidationResult(BaseValidationResult):
self.headers = headers
def get_operation_pattern(server_url, request_url_pattern):
"""Return an updated request URL pattern with the server URL removed."""
if server_url[-1] == "/":
# operations have to start with a slash, so do not remove it
server_url = server_url[:-1]
if URL(server_url).is_absolute():
return request_url_pattern.replace(server_url, "", 1)
return URL(request_url_pattern).path_qs.replace(server_url, "", 1)
class RequestValidator(object):
def __init__(self, spec):
@ -68,8 +79,9 @@ class RequestValidator(object):
errors.append(exc)
return RequestValidationResult(errors, body, parameters)
operation_pattern = request.full_url_pattern.replace(
server.default_url, '')
operation_pattern = get_operation_pattern(
server.default_url, request.full_url_pattern
)
try:
operation = self.spec.get_operation(
@ -154,8 +166,9 @@ class ResponseValidator(object):
errors.append(exc)
return ResponseValidationResult(errors, data, headers)
operation_pattern = request.full_url_pattern.replace(
server.default_url, '')
operation_pattern = get_operation_pattern(
server.default_url, request.full_url_pattern
)
try:
operation = self.spec.get_operation(

View file

@ -1,2 +1,3 @@
openapi-spec-validator
six
yarl

View file

@ -0,0 +1,10 @@
openapi: "3.0.0"
info:
title: Minimal valid OpenAPI specification
version: "0.1"
paths:
/status:
get:
responses:
default:
description: Return the API status.

View file

@ -0,0 +1,12 @@
openapi: "3.0.0"
info:
title: Minimal valid OpenAPI specification with explicit 'servers' array
version: "0.1"
servers:
- url: /
paths:
/status:
get:
responses:
default:
description: Return the API status.

View file

@ -0,0 +1,49 @@
import pytest
from openapi_core.exceptions import InvalidOperation
from openapi_core.shortcuts import create_spec
from openapi_core.validators import RequestValidator
from openapi_core.wrappers import MockRequest
class TestMinimal(object):
servers = [
"http://minimal.test/",
"https://bad.remote.domain.net/",
"http://localhost",
"http://localhost:8080",
"https://u:p@a.b:1337"
]
spec_paths = [
"data/v3.0/minimal_with_servers.yaml",
"data/v3.0/minimal.yaml"
]
@pytest.mark.parametrize("server", servers)
@pytest.mark.parametrize("spec_path", spec_paths)
def test_hosts(self, factory, server, spec_path):
spec_dict = factory.spec_from_file(spec_path)
spec = create_spec(spec_dict)
validator = RequestValidator(spec)
request = MockRequest(server, "get", "/status")
result = validator.validate(request)
assert not result.errors
@pytest.mark.parametrize("server", servers)
@pytest.mark.parametrize("spec_path", spec_paths)
def test_invalid_operation(self, factory, server, spec_path):
spec_dict = factory.spec_from_file(spec_path)
spec = create_spec(spec_dict)
validator = RequestValidator(spec)
request = MockRequest(server, "get", "/nonexistent")
result = validator.validate(request)
assert len(result.errors) == 1
assert isinstance(result.errors[0], InvalidOperation)
assert result.body is None
assert result.parameters == {}