Microservices builder


License
MIT
Install
pip install microservices==0.33.0

Documentation

Microservices

Status: lib is under active development.

Build Status Code Climate Coverage Status PyPI Version

Build microservices and client easily.

HTTP service is based on the Browsable Web APIs for Flask

HTTP client uses wonderful requests lib

Queues service and client are both based on kombu


Overview

Microservices library provides you with helpers to create microservices and client apps.

See full documentation on Read the Docs

Library is currently a work in progress, but all essential functions are already in place, so you can already start building your services with it. If you want to start using Microservices right now, go ahead and do so, but be sure to follow the release notes of new versions carefully.

HTTP implementation: Screenshot

Roadmap

Coming features in version 1.0:

  • SQS, AMQP and other transport protocols for microservices API.
  • Full documentation
  • Classes for services building with microservices context.
  • Application layer

Installation

Requirements:

  • Python 2.7+ or 3.3+

Install using pip.

pip install microservices

Usage (http/rest)

Import and initialize your application (http)

from microservices.http.service import Microservice

app = Microservice(__main__)

Responses

Return any valid response object as normal, or return a list or a dict.

@app.route(
    '/example/',
    resource=Resource(),
)
def example():
    return {'hello': 'world'}

A renderer for the response data will be selected using content negotiation based on the client 'Accept' header. If you're making API request from a regular client, this will default to a JSON response. If you're viewing API via browser, it'll default to the browsable API HTML.

Requests

Access the parsed request data using request.data. This will handle JSON or form data by default.

@app.route(
    '/example/',
    resource=Resource(),
)
def example():
    return {'request data': request.data}

Example

The following example demonstrates a simple API for creating, listing, updating and deleting notes.

from microservices.http.service import Microservice
from microservices.http.runners import base_run as run
from microservices.http.resources import ResourceMarker
from microservices.utils import set_logging
from flask import request, url_for

microservice = Microservice(__name__)

@microservice.route(
    '/second/',
    resource=ResourceMarker()
)
def second():
    """Second resource

    * GET: return "SECOND"
    """
    return u'SECOND'

@microservice.route(
    '/second/',
    resource=ResourceMarker(),
    methods=['POST'],
)
def second_post():
    return request.data

@microservice.route(
    '/second/<string:test>/',
    resource=ResourceMarker(
        url_params=dict(test='something'),
    ),
    methods=['POST', 'GET'],
)
def second_params(test):
    """Second resource

    * POST: return request data
    * GET: return test param
    """
    if request.method == 'POST':
        return request.data
    return test

@microservice.route(
    '/second/<string:test>/<int:two>/',
    resource=ResourceMarker(
        url=lambda resource: url_for('second', _external=True),
    ),
    methods=['POST', 'GET'],
)
def second_params_two(test, two):
    """Second resource

    * POST: return [test, two, request data]
    * GET: return [test, two]
    """
    if request.method == 'POST':
        return [test, two, request.data]
    return [test, two]

@microservice.route(
    '/',
    endpoint='Hello, world!',
    methods=['GET', 'POST'],
    resource=ResourceMarker(),
)
def hello():
    """
    Hello, world resource, testing main page

    * GET: return POST something for hello
    * POST: return request data
    """
    if request.method == 'POST':
        return request.data
    return u"POST something for hello"

if __name__ == "__main__":
    set_logging()
    run(microservice, debug=True)

Now you can run your microservice:

$ python ./example.py
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader

And open http://127.0.0.1:5000/. You can then navigate between the notes and run GET, PUT, POST and DELETE API requests.

Client app example:

from microservices.http.client import Client
from microservices.utils import set_logging, get_logger

set_logging(level='INFO')
logger = get_logger('microservices client')

client = Client(
    'http://localhost:5000/',
)

logger.info(client.get(key='response'))
logger.info(client.post(data={'test': 'tested'}))

second_resource = client.resource('second')

logger.info(second_resource.get(key='response'))
logger.info(second_resource.post(data={'test': 'tested'}))

logger.info(second_resource.get('test', key='response'))
logger.info(second_resource.post('test'))

one_two_resource = second_resource.resource('one', '2')
logger.info(one_two_resource.get(key='response'))
logger.info(one_two_resource.post(data={'test': 'tested'}))

Result:

2016-06-16 14:11:10,997 - microservices.http.client - INFO - get: http://localhost:5000/
2016-06-16 14:11:11,000 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTP connection (1): localhost
2016-06-16 14:11:11,002 - microservices client - INFO - POST something for hello
2016-06-16 14:11:11,002 - microservices.http.client - INFO - post: http://localhost:5000/
2016-06-16 14:11:11,003 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTP connection (1): localhost
2016-06-16 14:11:11,004 - microservices client - INFO - {u'test': u'tested'}
2016-06-16 14:11:11,004 - microservices.http.client - INFO - get: http://localhost:5000/second/
2016-06-16 14:11:11,005 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTP connection (1): localhost
2016-06-16 14:11:11,006 - microservices client - INFO - SECOND
2016-06-16 14:11:11,006 - microservices.http.client - INFO - post: http://localhost:5000/second/
2016-06-16 14:11:11,007 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTP connection (1): localhost
2016-06-16 14:11:11,008 - microservices client - INFO - {u'test': u'tested'}
2016-06-16 14:11:11,008 - microservices.http.client - INFO - get: http://localhost:5000/second/test/
2016-06-16 14:11:11,009 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTP connection (1): localhost
2016-06-16 14:11:11,010 - microservices client - INFO - test
2016-06-16 14:11:11,010 - microservices.http.client - INFO - post: http://localhost:5000/second/test/
2016-06-16 14:11:11,011 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTP connection (1): localhost
2016-06-16 14:11:11,012 - microservices client - INFO - {}
2016-06-16 14:11:11,012 - microservices.http.client - INFO - get: http://localhost:5000/second/one/2/
2016-06-16 14:11:11,012 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTP connection (1): localhost
2016-06-16 14:11:11,014 - microservices client - INFO - [u'one', 2]
2016-06-16 14:11:11,014 - microservices.http.client - INFO - post: http://localhost:5000/second/one/2/
2016-06-16 14:11:11,015 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTP connection (1): localhost
2016-06-16 14:11:11,016 - microservices client - INFO - {u'response': [u'one', 2, {u'test': u'tested'}]}

Queues

Microservices 0.18.0+ support working with queues based on kombu

Example of service usage:

from microservices.queues.service import Microservice

# default uri: amqp:///
app = Microservice()

# queue name - "basic"
@app.queue('basic')
def basic_handler(payload, context):
    print(payload)

if __name__ == '__main__':
    app.run(debug=True)

Example of client usage:

from microservices.queues.client import Client

client = Client()

queue = client.queue('basic')
queue.publish({'data': 'Hello, world'})

Workers and ThreadPool:

from microservices.queues.service import Microservice

# Run application with 10 parallel's workers (microprocessing.pool.ThreadPool)
app = Microservice(workers=10)

Credits

Many thanks to Tom Christie for making the flask_api.