Skip to content
This repository has been archived by the owner on May 9, 2024. It is now read-only.

Commit

Permalink
Feature/method specific routes (#27)
Browse files Browse the repository at this point in the history
* adding custom http decorators

* Updating docs
  • Loading branch information
pdiazvargas authored Apr 19, 2019
1 parent 96a8db8 commit 423a714
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 5 deletions.
21 changes: 19 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function should look like:
app = Minik()
@app.route('/hello/{name}')
def hello_view(name):
def hello_view(name: str):
if name == 'FINDME':
# Returns a 400 status code with the message as the body.
Expand All @@ -52,7 +52,7 @@ define the methods, every single HTTP method will be allowed by default.
app = Minik()
@app.route('/events/{location}')
def events_view(location):
def events_view(location: str):
# This route will be invoked for GET, POST, PUT, DELETE...
return {'data': ['granfondo MD', 'Silver Spring Century']}
Expand All @@ -61,6 +61,23 @@ define the methods, every single HTTP method will be allowed by default.
create_event(app.request.json_body)
return {'result': 'complete'}
The microframework also includes a set of convenient decorator methods for the
case in which a view is associated with a single HTTP method.

.. code-block:: python
from minik.core import Minik
app = Minik()
@app.get('/events/{location}')
def get_view(location: str):
return {'data': ['granfondo MD', 'Silver Spring Century']}
@app.post('/events')
def post_view():
create_event(app.request.json_body)
return {'result': 'complete'}
Route Parameter Validation
**************************
Expand Down
21 changes: 20 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ define the methods, every single HTTP method will be allowed by default.
app = Minik()
@app.route('/events/{location}')
def events_view(location):
def events_view(location: str):
# This route will be invoked for GET, POST, PUT, DELETE...
return {'data': ['granfondo MD', 'Silver Spring Century']}
Expand All @@ -47,6 +47,25 @@ define the methods, every single HTTP method will be allowed by default.
create_event(app.request.json_body)
return {'result': 'complete'}
The microframework also includes a set of convenient decorator methods for the
case in which a view is associated with a single HTTP method.

.. code-block:: python
from minik.core import Minik
app = Minik()
@app.get('/events/{location}')
def get_view(location: str):
return {'data': ['granfondo MD', 'Silver Spring Century']}
@app.post('/events')
def post_view():
create_event(app.request.json_body)
return {'result': 'complete'}
Route Validation
****************
Using the `function annotations`_, you can specify the type of value you are expecting
Expand Down
18 changes: 16 additions & 2 deletions minik/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,26 @@ def sample_view(event_type):
"""

def __init__(self):
def __init__(self, **kwargs):
self._routes = defaultdict(list)

def get(self, path, **kwargs):
return self.route(path, methods=['GET'], **kwargs)

def post(self, path, **kwargs):
return self.route(path, methods=['POST'], **kwargs)

def put(self, path, **kwargs):
return self.route(path, methods=['PUT'], **kwargs)

def delete(self, path, **kwargs):
return self.route(path, methods=['DELETE'], **kwargs)

def route(self, path, **kwargs):
"""
The decorator function used to associate a given route with a view function.
:param path: The endpoint associated with a given view.
"""

def _register_view(view_func):
Expand Down Expand Up @@ -86,7 +100,7 @@ def __call__(self, event, context):
response = JsonResponse({'error_message': str(pe)}, status_code=pe.status_code)
except Exception as te:
tracer = ''.join(traceback.format_exc())
# self.logger.error(tracer)
print(tracer)
response = JsonResponse({'error_message': str(te), 'trace': tracer}, status_code=500)

return response.to_dict()
Expand Down
81 changes: 81 additions & 0 deletions tests/test_routing_decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
"""
test_routing_decorators.py
:copyright: © 2019 by the EAB Tech team.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

import json
import pytest
from unittest.mock import MagicMock
from minik.core import Minik


sample_app = Minik()
context = MagicMock()


@sample_app.route('/activity_no_method')
def no_method_view():
return {'method': sample_app.request.method.lower()}


@sample_app.post('/activity')
def post_view():
return {'id': 2, 'message': 'success'}


@sample_app.get('/activity/{activity_id}', validators=[True])
def get_view(activity_id: int):
return {'id': activity_id, 'type': 'cycling '}


@sample_app.put('/activity/{activity_id}')
def put_view(activity_id: int):
return {'updated': True}


@sample_app.delete('/activity/{activity_id}')
def delete_view(activity_id: int):
return {'removed': True}


def test_routing_for_http_post(create_router_event):

event = create_router_event('/activity',
method='POST',
body={'type': 'cycle', 'distance': 15})

response = sample_app(event, context)
expected_response = post_view()

assert response['body'] == json.dumps(expected_response)


@pytest.mark.parametrize("http_method, expected_response", [
('GET', get_view(123)),
('PUT', put_view(123)),
('DELETE', delete_view(123)),
])
def test_routing_for_http_get(create_router_event, http_method, expected_response):
"""
Validate that a view defined for a GET request is correctly evaluated when
the route + method match the signature.
"""

event = create_router_event('/activity/{activity_id}',
method=http_method,
pathParameters={'activity_id': 123})

response = sample_app(event, context)

assert response['body'] == json.dumps(expected_response)

0 comments on commit 423a714

Please sign in to comment.