Service

Service is component. You should use service when you need:

  • Carry big logic processing. Entry of main logic proccessing is handlers of controllers, when it too long, you should move it into services.
  • Reuse logic processing. May be some handlers must do same of logic processing, that borrow to write again and again, best way is services. That mean code is more easy to read, debug and maintain.
  • Access to shared resources. Shared resources is configurations, connection to database, it’s some things only exist during runtime. Service is most simple way to to do it because serivce is component and Injector give it’s dependencies automatically.

Clink also provides built-in services, check it out in clink.service

Example

Now, let create an service, share way to public newsparer or magazine. It accepts type and content of newsparer, magazine then generate string includes information of application with type and content. Two controllers use this service though injector.

service.py
# STEP 1: get clink library
from clink import stamp, mapper, App, AppConf, Controller, Service, Version
from clink.mime.type import MIME_PLAINTEXT
from bson import ObjectId


# STEP 2: get an WSGI server
from wsgiref.simple_server import make_server


# STEP 3: create application configuration and application
conf = AppConf('book-api', 'MIT License', Version(0, 1, 0),
               'Hell Corporation', '1st, Hell street')
app = App(conf)


# STEP 4: define components
# ===[BEGIN] DEFINE SERVICES =================================================
@stamp(AppConf)
class PubService(Service):
    def __init__(self, app_conf):
        self._app_conf = app_conf

    def publish(self, type, content):
        id = ObjectId()
        parts = (
            'Id: ', str(id), '\n',
            'Type: ', type, '\n',
            'Content:\n\n', content, '\n\n',
            self._app_conf.name,
            ' v', str(self._app_conf.version), '\n',
            self._app_conf.org_name, '\n',
            self._app_conf.org_addr,
        )
        return ''.join(parts)


@stamp(PubService)
@mapper.path('/newsparer')
class NewsCtl(Controller):
    def __init__(self, pub_sv):
        self._pub_sv = pub_sv

    @mapper.post('/', MIME_PLAINTEXT)
    def publish(self, req, res):
        content = req.body.decode('utf-8')
        pub = self._pub_sv.publish('NEWSPAPER', content)
        res.body = pub.encode('utf-8')
        res.content_type = MIME_PLAINTEXT


@stamp(PubService)
@mapper.path('/magazine')
class MagazineCtl(Controller):
    def __init__(self, pub_sv):
        self._pub_sv = pub_sv

    @mapper.post('/', MIME_PLAINTEXT)
    def publish(self, req, res):
        content = req.body.decode('utf-8')
        pub = self._pub_sv.publish('MAGAZINE', content)
        res.body = pub.encode('utf-8')
        res.content_type = MIME_PLAINTEXT

# ===[END] DEFINE SERVICES ===================================================


# STEP 5: add components to application
app.add_ctl(NewsCtl)
app.add_ctl(MagazineCtl)

# STEP 6: load components
app.load()

# STEP 7: serve application on WSGI server
address = 'localhost'
port = 8080
print('Prepare API on http://%s:%i' % (address, port))
httpd = make_server(address, port, app)
httpd.serve_forever()

Testing

$ python service.py &> /dev/null &
[1] 5864

$ curl -X POST -H "Content-Type: text/plain" \
  -d "This is awesome newsparer" localhost:8080/newsparer; echo
Id: 5920522fe7798916e88e93fd
Type: NEWSPAPER
Content:

This is awesome newsparer

book-api
Hell Corporation
1st, Hell street

$ curl -X POST -H "Content-Type: text/plain" \
  -d "This is awesome magazine" localhost:8080/magazine; echo
Id: 59be3309e779894758b26f86
Type: NEWSPAPER
Content:

This is awesome newsparer

book-api v0.1.0
Hell Corporation
1st, Hell street

$ kill %1