Introducing Helloworld Microservice

Goal

  • To build a helloworld microservice and run it on a single instance.

Discussion

Large technology organizations and problems involve “planet-scale” engineering and infrastructure. To solve scalable / distributed problems in such organizations, they need to consistently and rapidly deliver complex applications. Microservices architecture is an approach that constructs such applications as a collection of services that are:

  • loosely coupled
  • cohesive
  • independently deployable
  • reliable (fault tolerant)
  • scalable (cope with load)
  • maintainable
  • observable (telemetry)
  • independently evolvable

In this series of “lab exercises”, my hope is to be able to explore each of these tenets with concrete implemented examples.

To understand, appreciate and learn microservices architecture, a good starting point is to just build a simple barebones microservice, without the above-said tenets.

Infra

A single VM instance running on top of Hyper-V, provisioned it with Ubuntu 20.04 Live Server.

Stack

For this series, I am planning to build stuff using Python. So, generally choosing web/app tier technologies that play nice with it. Of course, these may change based on use case, but for our little helloworld microservice, we just need a Web Framework for Python to build a REST API and a Web Server to serve it. I decided to go with a fast, lightweight framework called FastAPI which works well with Uvicorn ASGI web server.

App Tier

DB / Cache Tier

  • Not needed

Architecture

Helloworld microservice Architecture Diagram

Setup

Let’s start at the start.

sudo apt update
sudo apt install python3 python3-pip

I will skip creating a virtual environment for our microservice since all this will eventually be dockerized.

Now, we are ready to install the other app tier tech (I will use pytest for writing tests, which in turn will need requests).

sudo pip3 install uvicorn[standard] fastapi requests pytest

Code

Using any editor, we write the following code (and call it helloworld.py).

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def root():
    return {"message": "Hello World"}

Here, app is an instance of FastAPI class and it will be the interface for the web server to interact with. We then create a function and add a decorator that indicates that this will serve GET requests coming to path “/”.

The function can be declared async, if it performs operations which can await. Support for asyncio, WebSocket and great performance are some of the key reasons why I like FastAPI + uvicorn.

We can put this inside a simple project structure, like:

─── helloworld/
    ├── app/
    │   ├── __init__.py
    │   └── helloworld.py
    ├── tests/
    │   ├── __init__.py
    │   └── test_helloworld.py
    ├── .gitignore
    ├── LICENSE
    └── README.md

The test_helloworld.py will look like:

from fastapi.testclient import TestClient
from app.helloworld import app

client = TestClient(app)

def test_read_main():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"message": "Hello World"}

To try this out, we will run it with uvicorn (ensuring that we use 0.0.0.0 so that it is exposed to the network):

uvicorn app.helloworld:app --host 0.0.0.0

We will get something like:

INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

The helloworld service is now accessible via any client using:

http://vm-ip-addr:8000/ 

We should receive a response like:

{"message":"Hello World"}

And as cherry on top, FastAPI comes with Swagger (OAS3) docs. So, we get a nice doc page as well:

http://vm-ip-addr:8000/docs

Summary

Nice! That will do for this exercise. We now have a helloworld microservice running on a single instance.

Onward we shall go!


Creative Commons License

Unless otherwise specified, this work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.