Skip to content

BMI Calculation API

Our introductory tutorial is to write a simple BMI calculation API, which calculates the corresponding BMI value according to the input height and weight.

1. Create project

We can create a project directly using

meta setup demo-bmi

Then you will be prompted to enter the description, host and other information, you can choose to skip, after that, you will get the following file structure

/bmi
    server.py
    meta.ini

server.py is your file with backend code, while meta.ini is a config file to store the project meta-data

2. Basic implementation

Open server.py, we can see that there is already a class named RootAPI

class RootAPI(api.API):
    @api.get
    def hello(self):
        return 'world'

Here you can see the simplest UtilMeta API, which uses a @api.get decorator to indicate that it is a GET method. The decorator does not specify a path, so the path of the API is the name of the function (/hello).

We write the BMI calculation API as follows

class RootAPI(api.API):  
    @api.get  
    def bmi(self, weight: float, height: float):  
         return round(weight / height ** 2, 1)

The parameters weight and height in the bmi function will become query parameters by default, which can be calculated in the function and returned directly. UtilMeta will wrap the return value to a HTTP response

We can run this file directly to start the API service.

python server.py

When you see the following info, it means that the startup is successful

Running on http://127.0.0.1:8000
Press CTRL+C to quit

Then we can use our browser to open http://127.0.0.1:8000/api/bmi?weight=70&height=1.85 to call the API, and we can see that the API returns

20.5

This example is simple enough, but it also has some areas that can be optimized, such as

  • The limitation of the requested parameter value was not verified. An error will occur if the parameter height is 0. and there is no meaning if the parameter is negative.
  • The number is returned directly as a result, and the normal practice is to use a JSON to return it.

3. Add params & response

Combined with the optimizations mentioned above, let’s make some improvements to the API.

First, we use utype.Param to add a declaration of validation rules for input parameters, as shown in

import utype

class RootAPI(api.API):
    @api.get
    def bmi(self,
            weight: float = utype.Param(gt=0, le=1000),
            height: float = utype.Param(gt=0, le=4)):
        return round(weight / height ** 2, 2)

In the above function, we declared that the weight parameter needs to be greater than 0 and less than or equal to 1000, and height the parameter needs to be greater than 0 and less than or equal to 4. If the input data does not conform to these rules, UtilMeta will automatically process and return a 400 BadRequest response.

utype

UtilMeta is based on utype to declare and parse params, you can discover more usage of validation ruls in this doc

For the return result, we can use a JSON to return the BMI value and classification. In order to make the response also integrated into the API document, we can use utype.Schema to define the format of the response, such as

from utilmeta.core import api
import utype

class BMISchema(utype.Schema):
    value: float = utype.Field(round=2)

    @property
    def level(self) -> int:
        for i, l in enumerate([18.5, 25, 30]):
            if self.value < l:
                return i
        return 3

class RootAPI(api.API):
    @api.get
    def bmi(self,
            weight: float = utype.Param(gt=0, le=1000),
            height: float = utype.Param(gt=0, le=4)
            ) -> BMISchema:
        return BMISchema(value=weight / height ** 2)

In BMISchema, we declare the level property, using value to calculate the corresponding BMI level, which will also be output as a field. The BMISchema instance returned by the API will be directly processed by UtilMeta into a JSON format response to the client.

When we restart the project and visit http://127.0.0.1:8000/api/bmi?weight=70&height=1.85 again, we can see the following return result

{"value": 20.45, "level": 1}

4. Connect API

Once your UtilMeta service is developed, you can connect it to view a debugable API document, The --ops argument we added in setup command inserted a UtilMeta Operations config automatically, we can see it in server.py

from utilmeta.ops.config import Operations

service.use(Operations(
    route='ops',
    database=Database(
        name='demo-bmi_utilmeta_ops',
        engine='sqlite3',
    ),
))

When the service is running, you can see the following output:

UtilMeta OperationsAPI loaded at http://127.0.0.1:8000/api/ops, connect your APIs at https://ops.utilmeta.com/localhost?local_node=http://127.0.0.1:8000/api/ops

You can click this link directly to open UtilMeta Platform and connect to your local service, or run this command in your project directory

meta connect

You will see a browser tab prompted up and connected to the APIs you just created

Click API will lead us to the BMI calculation API, We can click Debug to send a request

Click Log will direct you to view the API logs we just triggered, you can cliick the log row to view the detailed info.

Tip

For the performance of real-time requests, logs will be collected in the background of the process and stored regularly. If you don't see them immediately, you can wait and refresh them. For more information of Operations system you can refer to Connect API and Operations

Source Code

the source code of this tutorial can be found at github