Python Guide

We start with an empty directory on the file system.

$ mkdir status
$ cd status

Service Configuration

You can use Bootstrap page to start configuring your service. Here is our initial minimal configuration:

status.proto
syntax = "proto3";

package status;

import "harness/wire.proto";
import "harness/http.proto";

message Configuration {
    option (harness.service).name = "status";

    harness.http.Server server = 1 [
        (harness.wire).output.type = "harness.wires.aiohttp.web.ServerWire"
    ];
}

It only defines one wire - HTTP server used to serve requests.

Test

$ ls
status.proto

Requirements

In order to proceed, we have to install our runtime and build dependencies:

$ pip3 install "harness[sdk]" aiohttp

Note

These dependencies are great for development environments only, so:

  • You probably don’t have to install aiohttp in CI environment

  • You certainly don’t have to install [sdk] extras in runtime (production) environment

Code Generation

Here we generate runtime for our service:

python3 -m grpc_tools.protoc -I. -I$(harness proto-path) \
        --harness_out=runtime=python:. --python_out=. status.proto

Runtime consists of an entrypoint and a wires definition:

Test

$ ls
status.proto
status_pb2.py
status_wires.py
entrypoint.py

Runtime Configuration

Here we add our runtime configuration in the YAML format:

status.yaml
server:
  bind:
    host: 0.0.0.0
    port: 8000

Content of this file should conform to the Configuration message definition in the status.proto file.

Test

$ ls
status.proto
status_pb2.py
status_wires.py
entrypoint.py
status.yaml

Service Implementation

Here we add implementation of our service:

from aiohttp import web
from harness.wires.aiohttp.web import ServerWire

from status_pb2 import Configuration
from status_wires import WiresIn, WiresOut


async def index(request: web.Request) -> web.Response:
    return web.Response(text="OK")


async def setup(config: Configuration, wires_in: WiresIn) -> WiresOut:
    app = web.Application()
    app.router.add_get("/", index)
    return WiresOut(server=ServerWire(app))

It must contain a setup coroutine function, which accepts configuration and initialized input wires, and returns output wires. Everything else is up to you.

Test

$ ls
status.proto
status_pb2.py
status_wires.py
entrypoint.py
status.yaml
status.py

Finish

Now we can launch our service:

$ python3 entrypoint.py --help
usage: entrypoint.py [-h] [--merge MERGE] [--patch PATCH] config

positional arguments:
  config         Configuration file in the YAML format

optional arguments:
  -h, --help     show this help message and exit
  --merge MERGE  Merge config with a file
  --patch PATCH  Patch config with a file
$ python3 entrypoint.py status.yaml

Open http://localhost:8000/ url and check that your service is up and running. Now you can add more wires and implement your logic.

Test

$ curl http://localhost:8000/
OK

Note

Every time you change your configuration in the status.proto file, you must regenerate your runtime (see Code Generation section above).