Skip to content

Is310/valid api response #311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 67 commits into from
Nov 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
2741834
Fixes typos in client after bad merge
Jul 6, 2018
9646035
Merge remote-tracking branch 'upstream/master'
Jul 6, 2018
c3ad81c
Merge remote-tracking branch 'upstream/master'
Jul 6, 2018
d7b91f7
Merge remote-tracking branch 'upstream/master'
Jul 10, 2018
a65aa8e
Merge remote-tracking branch 'upstream/master'
Jul 11, 2018
4edc12a
Merge remote-tracking branch 'upstream/master'
Jul 16, 2018
460bdea
Merge remote-tracking branch 'upstream/master'
Jul 16, 2018
408990d
Merge remote-tracking branch 'upstream/master'
Jul 18, 2018
ee1b91b
Merge remote-tracking branch 'upstream/master'
Jul 20, 2018
cf7b3f4
Merge remote-tracking branch 'upstream/master'
Aug 9, 2018
3f4eed8
Merge remote-tracking branch 'upstream/master'
Aug 22, 2018
14cbec2
Merge remote-tracking branch 'upstream/master'
Aug 23, 2018
b57188b
Merge remote-tracking branch 'upstream/master'
Sep 3, 2018
66e5cdc
Merge remote-tracking branch 'upstream/master'
Sep 4, 2018
31aeb8f
Merge remote-tracking branch 'upstream/master'
Sep 13, 2018
c0dbe36
Merge remote-tracking branch 'upstream/master'
Sep 18, 2018
81111e0
Merge remote-tracking branch 'upstream/master'
Sep 19, 2018
6b4c1bf
Merge remote-tracking branch 'upstream/master'
Sep 24, 2018
bbe7558
Merge remote-tracking branch 'upstream/master'
Sep 25, 2018
fd2befe
Merge remote-tracking branch 'upstream/master'
Oct 10, 2018
6b0dd8f
Merge remote-tracking branch 'upstream/master'
Oct 12, 2018
b706243
Merge remote-tracking branch 'upstream/master'
Oct 17, 2018
0bf32b8
Merge remote-tracking branch 'upstream/master'
Oct 17, 2018
d0664c9
Merge remote-tracking branch 'upstream/master'
Oct 19, 2018
5e895e0
Merge remote-tracking branch 'upstream/master'
Oct 19, 2018
90eb8f4
Merge remote-tracking branch 'upstream/master'
Oct 19, 2018
dc90291
Merge remote-tracking branch 'upstream/master'
Oct 19, 2018
152d2cc
Merge remote-tracking branch 'upstream/master'
pcrespov Oct 22, 2018
4628a6e
Merge remote-tracking branch 'upstream/master'
pcrespov Oct 23, 2018
9c49147
Merge remote-tracking branch 'upstream/master'
Oct 24, 2018
21aeab8
Merge branch 'master' of github.com:pcrespov/osparc-simcore
Oct 24, 2018
62eb5c5
Merge remote-tracking branch 'upstream/master'
Oct 26, 2018
65f510c
Merge remote-tracking branch 'upstream/master'
Oct 29, 2018
9e40d37
Merge remote-tracking branch 'upstream/master'
Oct 30, 2018
77d6ac1
Merge remote-tracking branch 'upstream/master'
pcrespov Oct 31, 2018
e733846
Merge branch 'master' of github.com:pcrespov/osparc-simcore
Oct 31, 2018
6ca6aad
Merge remote-tracking branch 'upstream/master'
Oct 31, 2018
d423dcc
Merge remote-tracking branch 'upstream/master'
Nov 2, 2018
0fd2975
Merge remote-tracking branch 'upstream/master'
Nov 5, 2018
b9cad5a
Adding testing infrastructure. Basic test_package and config
Nov 5, 2018
1c43b5b
WIP: testing openapi response/request validators, routing
Nov 5, 2018
875df42
Cleanup and fixes on test oas
Nov 5, 2018
0174e51
servicelib middelwares
Nov 5, 2018
51d8b23
WIP: implementing validation as well (not working)
Nov 5, 2018
ff24de0
Encodes classes with attributes
Nov 5, 2018
bfda02f
Minor cleanup in test messaging
pcrespov Nov 5, 2018
8b646bf
WIP: changing all handles to coroutines
pcrespov Nov 6, 2018
fd80f23
service middlewares pass envelope tests
Nov 6, 2018
95dbca6
Updated middlewares in webserver
Nov 6, 2018
4102f4e
Updated middlewares in storage
Nov 6, 2018
6badb34
Added servicelib tests in makefile and fixes test requirements
Nov 6, 2018
a7b7889
Added tests for rest-routing functionality
Nov 6, 2018
64ee190
first version of openapi response validators pass
Nov 6, 2018
071b5eb
cleanup
Nov 6, 2018
bed21c1
Refactoring of rest sub-package
Nov 6, 2018
3f7ab96
Cleanup
Nov 6, 2018
f25d9de
Created middleware to deal with validation of request/responses
Nov 6, 2018
7eeb332
fixes linters and cleanup
Nov 6, 2018
6059729
Minor fixes in servicelib
Nov 6, 2018
78ffe64
Adapting storage and webserver to new rest_middlewares
Nov 6, 2018
6adeec1
Merged changes in webserver local and api/specs oas
Nov 6, 2018
71706f0
update api/specs/webserver
Nov 6, 2018
6f010a8
- Response validation fails if specs not in single-document
Nov 6, 2018
68f826c
Merge branch 'master' into is310/valid-api-response
pcrespov Nov 6, 2018
bcc2fcd
Merge branch 'is310/valid-api-response' of github.com:pcrespov/osparc…
Nov 6, 2018
ec69cc1
Minor cleanup of servicelib
Nov 7, 2018
8cc6505
Merge branch 'master' into is310/valid-api-response
pcrespov Nov 9, 2018
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ run_test:
pytest -v services/apihub/tests
pytest --cov=pytest_docker -v packages/pytest_docker/tests
pytest --cov=s3wrapper -v packages/s3wrapper/tests
pytest --cov=simcore_sdk -v packages/simcore-sdk/tests
pytest --cov=servicelib -v packages/service-library/tests
pytest --cov=simcore_service_webserver -v services/web/server/tests/unit
pytest --cov=simcore_service_webserver -v services/web/server/tests/login
pytest --cov=simcore_service_director -v services/director/tests
Expand Down
44 changes: 38 additions & 6 deletions api/specs/webserver/v0/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,25 @@ info:
url: https://github.com/ITISFoundation/osparc-simcore/blob/master/LICENSE
servers:
- description: Development server
url: http://{host}:{port}/v0
url: http://{host}:{port}/{basePath}
variables:
host:
default: 'localhost'
port:
default: '8001'
basePath:
enum:
- v0
default: v0
- description: Production server
url: https://webserver:{port}/v0
url: '{publicUrl}/{basePath}'
variables:
port:
default: '9081'
publicUrl:
default: 'https://osparc.io'
basePath:
enum:
- v0
default: v0
tags:
- name: admins
description: Secured Admin-only calls
Expand Down Expand Up @@ -98,6 +106,8 @@ paths:
application/json:
schema:
$ref: './components/schemas/log_message.yaml#/LogMessageEnveloped'
'400':
$ref: '#/components/responses/DataError_BadRequest_400'
'409':
$ref: '#/components/responses/DataError_Conflict_409'
'422':
Expand Down Expand Up @@ -127,6 +137,7 @@ paths:
$ref: '#/components/responses/DefaultErrorResponse'
/auth/logout:
get:
operationId: auth_logout
responses:
'200':
description: Succesfully logged out
Expand All @@ -137,7 +148,28 @@ paths:
default:
$ref: '#/components/responses/DefaultErrorResponse'
#/auth/reset-password:
#/auth/change-email:
/auth/change-email:
post:
operationId: auth_change_email
requestBody:
content:
application/json:
schema:
type: object
properties:
new_email:
type: string
#format: email
responses:
'200':
description: User has been succesfully registered.
content:
application/json:
schema:
$ref: './components/schemas/log_message.yaml#/LogMessageEnveloped'
default:
$ref: '#/components/responses/DefaultErrorResponse'

#/auth/change-password:
/auth/confirmation/{code}:
get:
Expand All @@ -148,7 +180,7 @@ paths:
required: true
schema:
type: string
format: uuid
#format: uuid
responses:
default:
$ref: '#/components/responses/OK_NoContent_204'
Expand Down
7 changes: 4 additions & 3 deletions packages/service-library/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,14 @@ docs: ## generate Sphinx HTML documentation, including API docs
servedocs: docs ## compile the docs watching for changes
watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .

release: dist ## package and upload a release
twine upload dist/*

dist: clean ## builds source and wheel package
python setup.py sdist
python setup.py bdist_wheel
ls -l dist

install: clean ## install the package to the active Python's site-packages
python setup.py install

dev: clean
pip install -r requirements/dev.txt
pip list
3 changes: 1 addition & 2 deletions packages/service-library/requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@
bumpversion
coverage

pytest==3.4.2
pytest-runner==2.11.1
-r ../tests/requirements.txt
1 change: 0 additions & 1 deletion packages/service-library/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ def list_packages(*parts):
'License :: OSI Approved :: MIT License',
'Natural Language :: English',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
],
long_description=readme + '\n\n' + history,
license="MIT license",
Expand Down
8 changes: 3 additions & 5 deletions packages/service-library/src/servicelib/aiopg_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
import logging
import warnings

log = logging.getLogger(__name__)
logger = logging.getLogger(__name__)

warnings.warn("DO NOT USER, STILL UNDER DEVELOPMENT")
warnings.warn("DO NOT USE IN PRODUCTION, STILL UNDER DEVELOPMENT")

@attr.s(auto_attribs=True)
class AiopgExecutor:
Expand Down Expand Up @@ -42,9 +42,7 @@ def _compile(self, sql, *multiparams, **params):

async def execute(self):
async with self.engine.acquire() as conn:
log.debug(self.statement)
import pdb; pdb.set_trace()

logger.debug(self.statement)
resp = await conn.execute(self.statement)
return resp

Expand Down
7 changes: 6 additions & 1 deletion packages/service-library/src/servicelib/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@
OAI_VERSION = '3.0.1'
OAI_VERSION_URL = 'https://github.com/OAI/OpenAPI-Specification/blob/master/versions/%s.md'%OAI_VERSION

# alias
OpenApiSpec = Spec


# TODO: ensure openapi_core.__version__ is up-to-date with OAI_VERSION

def create_specs(openapi_path: Path) -> Spec:
def create_specs(openapi_path: Path) -> OpenApiSpec:
# TODO: spec_from_file and spec_from_url
with openapi_path.open() as f:
spec_dict = yaml.safe_load(f)

Expand Down
28 changes: 25 additions & 3 deletions packages/service-library/src/servicelib/openapi_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
from openapi_core import shortcuts
from openapi_core.schema.specs.models import Spec as OpenApiSpec
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.validation.response.validators import ResponseValidator

from .openapi_wrappers import (PARAMETERS_KEYS, AiohttpOpenAPIRequest,
AiohttpOpenAPIResponse)

log = logging.getLogger(__name__)
logger = logging.getLogger(__name__)

#from openapi_core.wrappers.mock import MockRequest

Expand All @@ -32,7 +33,6 @@ async def validate_request(request: web.Request, spec: OpenApiSpec):

return result.parameters, result.body, result.errors


async def validate_parameters(spec: OpenApiSpec, request: web.Request):
req = await AiohttpOpenAPIRequest.create(request)
return shortcuts.validate_parameters(spec, req)
Expand All @@ -41,6 +41,9 @@ async def validate_body(spec: OpenApiSpec, request: web.Request):
req = await AiohttpOpenAPIRequest.create(request)
return shortcuts.validate_body(spec, req)




async def validate_data(spec: OpenApiSpec, request, response: web.Response):

if isinstance(request, web.Request):
Expand All @@ -58,7 +61,26 @@ async def validate_data(spec: OpenApiSpec, request, response: web.Response):
req = request

res = await AiohttpOpenAPIResponse.create(response)
return shortcuts.validate_data(spec, req, res)

validator = ResponseValidator(spec)
result = validator.validate(req, res)

result.raise_for_errors()

return result.data

async def validate_response(spec: OpenApiSpec, request: web.Request, response: web.Response):
"""
Validates server response against openapi specs

Raises exceptions OpenAPIError, OpenAPIMappingError
"""
validator = ResponseValidator(spec)

req = await AiohttpOpenAPIRequest.create(request)
res = AiohttpOpenAPIResponse(response, response.text) # FIXME:ONLY IN SERVER side. Async in client!
result = validator.validate(req, res)
result.raise_for_errors()


__all__ = (
Expand Down
14 changes: 9 additions & 5 deletions packages/service-library/src/servicelib/openapi_wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

CAPTURES = re.compile(r'\(\?P<([_a-zA-Z][_a-zA-Z0-9]+)>(.[^)]+)\)')
PARAMETERS_KEYS = ('path', 'query', 'header', 'cookie')
PATH_KEY, QUERY_KEY, HEADER_KEY, COOKIE_KEY = PARAMETERS_KEYS

class AiohttpOpenAPIRequest(BaseOpenAPIRequest):
wrappedcls = web.Request
Expand Down Expand Up @@ -109,16 +110,19 @@ class AiohttpOpenAPIResponse(BaseOpenAPIResponse):

def __init__(self, response: web.Response, data: str):
self._response = response
self._data = data
self._text = data

@staticmethod
async def create(response: web.Response):
data = await response.text()
return AiohttpOpenAPIResponse(response, data)
text = await response.text()
return AiohttpOpenAPIResponse(response, text)

@property
def data(self) -> str:
return self._data
def body(self) -> str:
return self._text

# BUG: not part of BaseOpenAPIResponse but used in openapi-core
data = body

@property
def status_code(self) -> int:
Expand Down
11 changes: 6 additions & 5 deletions packages/service-library/src/servicelib/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pathlib
import pkg_resources
from pathlib import Path
#import typing
from typing import TextIO
import attr


Expand All @@ -21,16 +21,17 @@ class ResourcesFacade:
distribution_name: str
config_folder: str

def exists(self, resource_name: str):
def exists(self, resource_name: str) -> bool:
return pkg_resources.resource_exists(self.package_name, resource_name)

def stream(self, resource_name: str):
def stream(self, resource_name: str) -> TextIO:
# TODO: check if read-only and if so, rename
return pkg_resources.resource_stream(self.package_name, resource_name)

def listdir(self, resource_name: str):
def listdir(self, resource_name: str) -> str:
return pkg_resources.resource_listdir(self.package_name, resource_name)

def isdir(self, resource_name: str):
def isdir(self, resource_name: str) -> str:
return pkg_resources.resource_isdir(self.package_name, resource_name)

def get_path(self, resource_name: str) -> Path:
Expand Down
44 changes: 0 additions & 44 deletions packages/service-library/src/servicelib/response_utils.py

This file was deleted.

24 changes: 24 additions & 0 deletions packages/service-library/src/servicelib/rest_codecs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
""" rest - json data encoders/decodes

"""
import attr
import json


class DataEncoder(json.JSONEncoder):
"""
Customized json encoder for rest data models

Extra encoding of:
- attr.s-like classes

TODO: extend to more types like apiset
"""
def default(self, o): #pylint: disable=E0202
if attr.has(o.__class__):
return attr.asdict(o)
return json.JSONEncoder.default(self, o)


def jsonify(payload):
return json.dumps(payload, cls=DataEncoder)
Loading