Upload
stratoscale
View
541
Download
1
Embed Size (px)
Citation preview
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
HammockA Good Place to REST
June, 2016Eyal Posener [email protected]
Software Engineer / Stratoscale
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Agenda
❏ Nice to meet you - I’m Eyal❏ Software developer at Stratoscale (~2 years)
❏ Why am I presenting Hammock?❏ Stratoscale has moved to microservices in containers:
❏ Currently 8 internally developed REST services.❏ Internal & external communication.
❏ Coverage:1. Creating a simple REST application with Python.2. What was missing for Stratoscale.3. Hammock
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Introducing WSGI - (Web Server Gateway Interface)Web Server Gateway Interfa
PEP 3333 / PEP 333 Web Server Gateway Interface.❏ Defines a simple API between the server/gateway and framework(/application).
Server/ Gateway
Framework
WSGI
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Many Many WSGI Players
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Application
An application is developed with a specific framework.
Server/ Gateway
Framework
WSGI Application
Framework API
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Let’s build a REST Server in Falcon
❏ REpresentational State Transfer❏ A convention for communication:
Path pattern HTTP method Action Status
(usually)Response(usually)
Request Args Location
.../<item>s POST Create new item 201/202 Dict Body
.../<item>s GET List all Items 200 List of dicts Query
.../<item>s/<item>_id
GET Get <item> 200 Dict Query
.../<item>s/<item>_id
PATCH/PUT Update <item> 202 Dict Body
.../<item>s/<item>_id
DELETE Delete <item> 204 Nothing Query
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
class Files(object): def on_post(self, req, resp): # create pass
def on_get(self, req, resp): # list pass
class File(object): def on_get(self, req, resp, file_id): # get one pass
def on_delete(self, req, resp, file_id): # delete pass
def on_patch(self, req, resp, file_id): # update pass
app = falcon.API()app.add_route('/files', Files())app.add_route('/files/{file_id}', File())
Falcon Application Example
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
import files # Business logic is here
class Files(object): def on_get(self, req, resp): """List files""" # First, extract request arguments path = req.get_param('path', required=True) sort = req.get_param('sort', default='modified') reverse = req.get_param('reverse', default=False) # Convert arguments if a specific type is required reverse = reverse == 'True' # Here we actually do stuff try: result = [f.to_dict for f in files.list(path, sort, reverse)] except OSError: raise falcon.HTTPNotFound('No path {}'.format(path)) # When all ready, prepare the response result_string = json.dumps(result) resp.status = falcon.HTTP_200 resp.body = result_string resp.content_type = 'application/json'
Falcon Application Example (cont.)
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
WSGI Deficiencies
To do the same work: Different framework == different applicationOnce you choose a framework, you are locked in!
Server/ Gateway
Application2
Application1
Application3
WSGI
API 1
API 2
API 3
Application4
API 4
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
REST Frameworks: Same Same but Different
Same same But DifferentMethods that do something with request and response objects.
● Some accept request and response objects.● Some accept requests and return responses.● Some magically have the request.● Some accept URL arguments.● Some convert return value to a response.● Some can read/write from the resource class methods.
Register of Python methods/classes on URLs.
● Some use resource classes.● Some use resource methods.● Some use both.● For some the class is only for a specific URL, for some it is
for a resource.
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
REST Frameworks: Same Same but Different (cont)
Same same But DifferentError handling ● Some catch a specific exception types.
● Some need a response object returned.
Their own Request/Response object
They were made for web serving
With REST extensions.
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Hammock
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Hammock
1.Abstraction2.Built for REST & developer
friendly3.Many cool features
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
1. Hammock Abstraction
Application
Hammock
Server/ Gateway
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Hammock Abstraction
Server/ Gateway
Well… to be honest....
Application
Hammock
WIP
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
2. Ease of Use: Handlers
class Files(hammock.Resource):
@hammock.get('/') def list(self, path, sort='modified', reverse=False, type=None): """ List files in directory. :param str path: Path to list files in. :param str type: Show only files of type. :param str sort: Sort files by attribute :param bool[False] reverse: Sort reverse. :return list: List of files. """ try: return [f.to_dict for f in files.list(path, sort, reverse)] except OSError: raise exceptions.NotFound('No path {}'.format(path))
@hammock.get('/{file_id}') def get(self, file_id) ...
Don't worry about converting requests to arguments.
Don't worry about converting results to responses.
Simply write Python
functions
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
2. Ease of Use: Some Corner Cases
Hammock has some reserved arguments.# streams
@hammock.post()def func(self, _file): # get octet/stream
return open(‘path’, ‘r’) # return octet/stream
# headers
@hammock.post()def func(self, _headers): # get headers
return {‘_headers’: {‘key1’: ‘value1’}} # return headers
# when request body is a list
@hammock.post()def func(self, _list): # get a list body
return [] # return list
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
2. Ease of Use: Resource Registering
Use a package structure to build URLs:resources/ hotels/ hotels.py /hotels rooms/ rooms.py /hotels/{hotel_id}/rooms reservations.py /hotels/{hotel_id}/rooms/{room_id}/reservations customers.py /customers
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
3. Many COOL Features
Hammock
Free Python client!
Free CLIAuthorizationenforcement
Free API documentation
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
How does it work?? At Server Startup:
app = hammock.Hammock(‘falcon’, resources)
❏ Iterate over a 'resources' package, collect all decorated route methods into a dict:{path: {method: function}}
❏ Register handlers using a backend API.
❏ The handler is a translator between backend handler to the function.
class Files(object): def on_post(self, req, resp): ...
class File(object): def on_get(self, req, resp, file_id): ...
app.add_route('/files', Files())app.add_route('/files/{file_id}', File())
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
How does it work?? Upon request:
Backend Request
Backend Response
Hammock
Request
Hammock
Response
Method Argumen
ts
Method Result
Backend Framewor
k
Decorated
Method
There is a lot of magic there...
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Future work
❏ More frameworks! (maybe you wanna help?)❏ Scheme validation.❏ Combine with swagger/RAML.❏ Improve unit testing infra.❏ And much more :-)
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Questions?
❏ Contact:[email protected]
❏ Install:pip install hammock-rest>>> import hammock
❏ Contribute:git clone https://github.com/Stratoscale/hammock.git
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Performance
Property Falcon Hammock Ratio Remarks
Document Length [bytes] 638 601 1.06 ujson :-)
Time taken for tests [seconds] 36.3 38 0.96
Requests per second [#/sec] (mean) 1378.5 1314.6 1.05
Time per request [ms] (mean) 0.725 0.761 0.95
Transfer rate [Kbytes/sec] received 955.8 864 1.11
Small benchmark with Apache bench for 50,000 GET requests that returns the same file list method.
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
WSGI
def app(environ, start_response): start_response('200 OK', [('Content-type',
'text/plain')]) return ['Hello world!\n']
® Copyright Stratoscale www.stratoscale.com @stratoscale +1 877 420 3244
Appendix
List of WSGI compliant servers.List of WSGI compliant frameworks.