[PYTHON] FastAPI Tutorial Memo Part 2 Path Parameters

Introduction

FastAPI Souce: https://github.com/tiangolo/fastapi FastAPI Document: https://fastapi.tiangolo.com

Target: Path Parameters (https://fastapi.tiangolo.com/tutorial/path-params/)

FastAPI tutorial notes.

This is a continuation of FastAPI Tutorial Note 1. FastAPI installation and server startup are the same as above, so please check the above article.

Basically, I refer to the official tutorial of Fast API, but I omit some parts or change the order for my own learning. Please refer to the official documentation for the correct and detailed information.

Since I am a beginner of Web & Python and rely on Google and DeepL for translation, I would appreciate it if you could point out any mistakes.

Development environment

Ubuntu 20.04 LTS Python 3.8.2 pipenv 2018.11.26

Target

--Understanding the ** Path parameter ** of FastAPI

procedure

Intro

FastAPI allows you to declare parameters and variables for paths in the same syntax as Python format. Save the following code as main.py.

main.py


from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id):
    return {"item_id": item_id}

At this time, the ʻitem_id of the decorator function@app.get ("/ items / {item_id}") is the ** Path parameter **, which is passed as the argument ʻitem_id to the function argument. As an example, after saving this file, start the server (ʻu vicorn main: app --reload) and open http://127.0.0.1:8000/items/foo in your browser. You should get a JSON-formatted text with the string foo assigned to the variable ʻitem_id, as shown below.

{"item_id":"foo"}

Actual screen

qiita_2_1 2020-07-12 22-53-23.png

This is the basis of the ** Path parameter ** in the Fast API.

Typed Path parameter

FastAPI allows you to declare the type of ** Path parameter ** inside a function using standard Python type annotations.

main


~
#Omission
~

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}

Notice the line ʻasync def read_item (item_id: int): that declares the function. Here, the argument ʻitem_id is declared as ʻint(integer type). Type declarations will give you editor support such as error checking and word completion. (In the above code, if I add numbers and strings likefoo = item_id +" bar "`, an error by Type Checker is displayed in my environment (PyCharm).)

If you open http://127.0.0.1:8000/items/3 with a browser with the function part of main.py changed to the above code, you will see the following.

{"item_id":3}

It should be noted here that the value received by the function read_item and displayed as the return value is not a string but an integer 3. By default, all input to the URL is interpreted as a string, but Python's type declaration automatically ** parsing ** (parses) the request and converts it to an integer type.

Http://127.0.0.1 with code that removes the part that declares the type as a trial (returns the part of ʻasync def read_item (item_id: int): to ʻasync def read_item (item_id):) If you access: 8000 / items / 3, it will be displayed as the string " 3 ".

{"item_id":"3"}

Also, if you access the Path parameter declared as ʻint` type with a URL like http://127.0.0.1:8000/items/foo, the following Http error will be returned.

{
    "detail": [
        {
            "loc": [
                "path",
                "item_id"
            ],
            "msg": "value is not a valid integer",
            "type": "type_error.integer"
        }
    ]
}

This is because the given parameter (str type" foo ") cannot be converted to ʻinttype, so the ** Data validation ** function of FastAPI worked. Similar to thestr type above, if you give a floating point float` type (such as http://127.0.0.1:8000/items/4.2) you will get a similar error.

In addition, it was confirmed that if a value of ʻinttype is given to a parameter declared withfloat` type, it will be converted.

From the above, you can see that the Fast API performs exactly the same validation as the Python type declaration.

Notice that the error message also specifies the point where validation did not pass (in this case the " path " parameter variable " item_id "). It will be very useful for developing and debugging code that interacts with the API.

Preventing bugs by type checking is one of the important features of FastAPI.

Check the document

After checking the above code, check http://127.0.0.1:8000/docs in your browser. The interactive API documentation is automatically generated, as shown below. (Click the blue tab labeled GET under default near the center of the screen to expand it.)

qiita_2_2 2020-07-13 19-25-40.png

There is ʻinteger under Name ʻitem_id of Parameters. You can see that the Python type declaration is also reflected in the interactive documentation (integrated into the Swagger UI). This document gives you a lot of information about the API and can be shared with designers and frontside people.

In addition, this document is based on the schema generated by FastAPI, but the generated schema is OpenAPI compliant, and various compatible tools have been developed. As I confirmed in Memo 1, there is an alternative document using ReDoc in FastAPI. Try accessing http://127.0.0.1:8000/redoc.

qiita_2_3 2020-07-13 19-40-37.png

It's a rough personal impression, but Swagger UI is an interactive document that can actually generate a request and check the result, while ReDoc is a static and simple document. Perhaps there are more ways to use it and other tools, but I'm not sure at all due to lack of study. I'm sorry. I would like to update it as soon as I learn.

For now, I feel that the Swagger UI, which can generate requests and see the results, is convenient.

Pydantic Returning to the main topic, all type annotations that are useful for document generation like this are done by a library called ** Pydantic **. The following article was helpful for Pydantic. Introduction to Pydantic @ 0622okakyo

** Pydantic ** allows many data types such as str, float, bool to be type-annotated in the same way.

Order problem in Path Operation

When creating a Path Operation, the path may become fixed.

As an example, suppose you have a path called / users / me for users to get their own data. At this time, let's assume that there is also a path called / users / {user_id} that retrieves data about another user at the same time using ʻuser_id`.

Path Operation in FastAPI is evaluated in order. Therefore, the path / users / me must be declared before the path/ users / {user_id}as shown below.

main


from fastapi import FastAPI

app = FastAPI()


@app.get("/users/me")
async def read_user_me():
    return {"user_id": "the current user"}


@app.get("/users/{user_id}")
async def read_user(user_id: str):
    return {"user_id": user_id}

If the path / users / me is declared after the path/ users / {user_id}as shown below, the value me will be passed to the FastAPI as a parameter ʻuser_id`.

main_miss


from fastapi import FastAPI

app = FastAPI()


@app.get("/users/{user_id}")  # <- "/users/me"If you can get the GET method"me"Is passed
async def read_user(user_id: str):
    return {"user_id": user_id}


@app.get("/users/me")   # <- "/users/me"This function is not called because has already been evaluated
async def read_user_me():
    return {"user_id": "the current user"}

Predefined values

If you have a Path Operater that accepts path parameters and you want to predefine valid values for those parameters, we recommend using the Python standard module ʻEnum`.

First, let's create an ʻEnum` class.

Import ʻEnum and create a subclass that inherits str and ʻEnum. By inheriting str, the API document can know in advance that the value to be set is a string type, and it will be rendered correctly.

Next, create a class attribute with a fixed value that is a valid value.

main


from enum import Enum   # <-Import Enum

from fastapi import FastAPI


class ModelName(str, Enum): # <-Class inheritance
    alexnet = "alexnet"     # <-Class attributes(Fixed value)Creation
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()

We will define the path parameters using the defined class.

Use the created enum class (ModelName) to create a path parameter with type annotations.

main


from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/model/{model_name}")
async def get_model(model_name: ModelName): # <-Path parameter with type annotation
    if model_name == ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

Check the documentation (http://127.0.0.1:8000/docs). The values available for path parameters are predefined, so the document interactively displays and selects those values.

  1. Click the GET tab and then click Try it out at the top of the tab.
  2. model_name becomes selectable.
  3. You can submit a request by selecting a value and clicking ʻExecte`.

(The screenshot below is taken from the Official Document. I couldn't get a screenshot of the selection screen well in my environment. )

qiita_2_4 2020-07-13 23-00-54.png

About enums

main


from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/model/{model_name}")
async def get_model(model_name: ModelName):
    if model_name == ModelName.alexnet: # <- ①
        return {"model_name": model_name, "message": "Deep Learning FTW!"}  # <- ③

    if model_name.value == "lenet": # <- ②
        return {"model_name": model_name, "message": "LeCNN all the images"}    # <- ③ 

    return {"model_name": model_name, "message": "Have some residuals"}     # <- ③ 

For more information, please refer to Python official document enum --- Support for enums.

Here, compare with the created ModelName enumeration type member (①), get the enumeration type value by .value and compare it (②), and use the enumeration type member as the return value (③). I have. Even in the case of a nested JSON body like the dictionary type dict, it is possible to return the value of Path Operater as an enum member. In this case, it is converted to the corresponding value (str in the above) and returned to the client.

If you get it in an interactive document or browser, you'll get a JSON return value like this, for example.

{
  "model_name": "alexnet",
  "message": "Deep Learning FTW!"
}

Path parameters including path

For example, suppose you have a Path Operation with the path / files / {file_path}. But if file_path itself has a path as a value (like file_path = home / johndoe / myfile.txt), The URL will look like this:

http://127.0.0.1:8000/files/home/johndoe/myfile.txt

OpenAPI does not support the declaration of path parameters with paths as values as described above because it leads to the definition of tests and the occurrence of difficult scenarios.

However, by using Starlette's internal tools, the Fast API allows you to declare such path parameters. (However, it is not possible to confirm that the path parameter itself contains the path in the API document that conforms to OpenAPI. * The document itself works)

Declare the path parameter, including the path, using a URL similar to the following:

/files/{file_path:path}

In the above, the path parameter is file_path, and the: path part specifies that the path parameter contains the path.

The usage example is as follows.

main


from fastapi import FastAPI

app = FastAPI()


@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
    return {"file_path": file_path}

At the end

Next time it will be a query parameter.

Recommended Posts

FastAPI Tutorial Memo Part 2 Path Parameters
FastAPI Tutorial Memo Part 3 Query Parameters
FastAPI Tutorial Memo Part 1
django tutorial memo
Python OpenCV tutorial memo
FastAPI Tutorial Memo Part 1
pyramid tutorial notes (single_file_tasks)
FastAPI Tutorial Memo Part 3 Query Parameters
FastAPI Tutorial Memo Part 2 Path Parameters
django tutorial memo
[For memo] Linux Part 2
List memo writing part 2
Python basic memo --Part 2
Python OpenCV tutorial memo
Python basic memo --Part 1
Android HCE Survey Memo (Part 2)
Linux standard textbook memo 1 part 2
Python Basic Grammar Memo (Part 1)
Linux standard textbook memo part 6