FastAPI – Response Model

FastAPI – Response Model ”; Previous Next An operation function returns A JSON response to the client. The response can be in the form of Python primary types, i.e., numbers, string, list or dict, etc. It can also be in the form of a Pydantic model. For a function to return a model object, the operation decorator should declare a respone_model parameter. With the help of response_model, FastAPI Converts the output data to a structure of a model class. It validates the data, adds a JSON Schema for the response, in the OpenAPI path operation. One of the important advantages of response_model parameter is that we can format the output by selecting the fields from the model to cast the response to an output model. Example In the following example, the POST operation decorator receives the request body in the form of an object of the student class (a subclass of BaseModel). As one of the fields in this class, i.e. marks (a list of marks) is not needed in the response, we define another model called percent and use it as the response_model parameter. from typing import List from fastapi import FastAPI from pydantic import BaseModel, Field app = FastAPI() class student(BaseModel): id: int name :str = Field(None, title=”name of student”, max_length=10) marks: List[int] = [] percent_marks: float class percent(BaseModel): id:int name :str = Field(None, title=”name of student”, max_length=10) percent_marks: float @app.post(“/marks”, response_model=percent) async def get_percent(s1:student): s1.percent_marks=sum(s1.marks)/2 return s1 If we check the Swagger documentation, it shows that the “/marks” route gets an object of student class as the request body. Populate the attributes with appropriate values and execute the get_percent() function. The server response is cast to the percent class as it has been used as the response_model. Print Page Previous Next Advertisements ”;

FastAPI – Nested Models

FastAPI – Nested Models ”; Previous Next Each attribute of a Pydantic model has a type. The type can be a built-in Python type or a model itself. Hence it is possible to declare nested JSON “objects” with specific attribute names, types, and validations. Example In the following example, we construct a customer model with one of the attributes as product model class. The product model in turn has an attribute of supplier class. from typing import Tuple from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class supplier(BaseModel): supplierID:int supplierName:str class product(BaseModel): productID:int prodname:str price:int supp:supplier class customer(BaseModel): custID:int custname:str prod:Tuple The following POST operation decorator renders the object of the customer model as the server response. @app.post(”/invoice”) async def getInvoice(c1:customer): return c1 The swagger UI page reveals the presence of three schemas, corresponding to three BaseModel classes. The Customer schema when expanded to show all the nodes looks like this − An example response of “/invoice” route should be as follows − { “custID”: 1, “custname”: “Jay”, “prod”: [ { “productID”: 1, “prodname”: “LAPTOP”, “price”: 40000, “supp”: { “supplierID”: 1, “supplierName”: “Dell” } } ] } Print Page Previous Next Advertisements ”;

FastAPI – Accessing Form Data

FastAPI – Accessing Form Data ”; Previous Next Now we shall see how the HTML form data can be accessed in a FastAPI operation function. In the above example, the /login route renders a login form. The data entered by the user is submitted to /submit URL with POST as the request method. Now we have to provide a view function to process the data submitted by the user. FastAPI has a Form class to process the data received as a request by submitting an HTML form. However, you need to install the python-multipart module. It is a streaming multipart form parser for Python. pip3 install python-multipart Add Form class to the imported resources from FastAPI from fastapi import Form Let us define a submit() function to be decorated by @app.post(). In order to receive the form data, declare two parameters of Form type, having the same name as the form attributes. @app.post(“/submit/”) async def submit(nm: str = Form(…), pwd: str = Form(…)): return {“username”: nm} Press submit after filling the text fields. The browser is redirected to /submit URL and the JSON response is rendered. Check the Swagger API docs of the /submit route. It correctly identifies nm and pwd as the request body parameters and the form’s “media type” as application/x-www-form-urlencoded. It is even possible to populate and return Pydantic model with HTML form data. In the following code, we declare User class as a Pydantic model and send its object as the server’ response. from pydantic import BaseModel class User(BaseModel): username:str password:str @app.post(“/submit/”, response_model=User) async def submit(nm: str = Form(…), pwd: str = Form(…)): return User(username=nm, password=pwd) Print Page Previous Next Advertisements ”;

FastAPI – Header Parameters

FastAPI – Header Parameters ”; Previous Next In order to read the values of an HTTP header that is a part of the client request, import the Header object from the FastAPI library, and declare a parameter of Header type in the operation function definition. The name of the parameter should match with the HTTP header converted in camel_case. In the following example, the “accept-language” header is to be retrieved. Since Python doesn’t allow “-” (dash) in the name of identifier, it is replaced by “_” (underscore) from typing import Optional from fastapi import FastAPI, Header app = FastAPI() @app.get(“/headers/”) async def read_header(accept_language: Optional[str] = Header(None)): return {“Accept-Language”: accept_language} As the following Swagger documentation shows, the retrieved header is shown as the response body. You can push custom as well as predefined headers in the response object. The operation function should have a parameter of Response type. In order to set a custom header, its name should be prefixed with “X”. In the following case, a custom header called “X-Web-Framework” and a predefined header “Content-Language” is added along with the response of the operation function. from fastapi import FastAPI from fastapi.responses import JSONResponse app = FastAPI() @app.get(“/rspheader/”) def set_rsp_headers(): content = {“message”: “Hello World”} headers = {“X-Web-Framework”: “FastAPI”, “Content-Language”: “en-US”} return JSONResponse(content=content, headers=headers) The newly added headers will appear in the response header section of the documentation. Print Page Previous Next Advertisements ”;

FastAPI – Rest Architecture

FastAPI – REST Architecture ”; Previous Next RElational State Transfer (REST) is a software architectural style. REST defines how the architecture of a web application should behave. It is a resource based architecture where everything that the REST server hosts, (a file, an image, or a row in a table of a database), is a resource, having many representations. REST recommends certain architectural constraints. Uniform interface Statelessness Client-server Cacheability Layered system Code on demand REST constraints has the following advantages − Scalability Simplicity Modifiability Reliability Portability Visibility REST uses HTTP verbs or methods for the operation on the resources. The POST, GET, PUT and DELETE methods perform respectively CREATE, READ, UPDATE and DELETE operations respectively. Print Page Previous Next Advertisements ”;

FastAPI – Crud Operations

FastAPI – CRUD Operations ”; Previous Next The REST architecture uses HTTP verbs or methods for the operation on the resources. The POST, GET, PUT and DELETE methods perform respectively CREATE, READ, UPDATE and DELETE operations respectively. In the following example, we shall use a Python list as an in-memory database and perform the CRUD operations on it. First, let us set up a FastAPI app object and declare a Pydantic model called Book. from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() data = [] class Book(BaseModel): id: int title: str author: str publisher: str An object of this model is populated using the @app.post() decorator and it is appended to the list of books (data is declared for the list of books) @app.post(“/book”) def add_book(book: Book): data.append(book.dict()) return data In the Swagger UI, execute this operation function a couple of times and add some data. The server’s JSON response shows the list of books added so far. To retrieve the list, define an operation function bound to the @app.get() decorator as follows − @app.get(“/list”) def get_books(): return data To retrieve a book with its id as a path parameter, define the get() operation decorator and get_book() function as below − @app.get(“/book/{id}”) def get_book(id: int): id = id – 1 return data[id] The /list route retrieves all the books. On the other hand, use “id” as the path parameter in the “/book/1” route. The book with “id=1” will be retrieved as can be seen in the server response of Swagger UI Next, define @app.put() decorator that modifies an object in the data list. This decorator too has a path parameter for the id field. @app.put(“/book/{id}”) def add_book(id: int, book: Book): data[id-1] = book return data Inspect this operation function in the swagger UI. Give id=1, and change value of publisher to BPB in the request body. When executed, the response shows the list with object with id=1 updated with the new values. Finally, we define the @app.delete() decorator to delete an object corresponding to the path parameter. @app.delete(“/book/{id}”) def delete_book(id: int): data.pop(id-1) return data Give id=1 as the path parameter and execute the function. Upon execution, the list now shows only two objects Print Page Previous Next Advertisements ”;

FastAPI – OpenAPI

FastAPI – OpenAPI ”; Previous Next Enter the following URL in the browser to generate automatically the interactive documentation. http://127.0.0.1:8000/docs FastAPI uses Swagger UI to produce this documentation. The browser will display the following − Click the ”try it out” button and then ”Execute” button that appears afterward. You can see the Curl command internally executed, the request URL, the response headers, and the JSON format of the server’s response. FastAPI generates a schema using OpenAPI specifications. The specification determines how to define API paths, path parameters, etc. The API schema defined by the OpenAPI standard decides how the data is sent using JSON Schema. Visit http://127.0.0.1:8000/openapi.json from your browser. A neatly formatted JSON response as follows will be displayed − { “openapi”: “3.0.2”, “info”: { “title”: “FastAPI”, “version”: “0.1.0” }, “paths”: { “/”: { “get”: { “summary”: “Index”, “operationId”: “index__get”, “responses”: { “200”: { “description”: “Successful Response”, “content”: { “application/json”: { “schema”: {} } } } } } } } } FastAPI also supports another automatic documentation method provided by Redoc ( https://github.com/Redocly/redoc). Enter http://localhost:8000/redoc as URL in the browser’s address bar. Print Page Previous Next Advertisements ”;

FastAPI – Path Parameters

FastAPI – Path Parameters ”; Previous Next Modern web frameworks use routes or endpoints as a part of URL instead of file-based URLs. This helps the user to remember the application URLs more effectively. In FastAPI, it is termed a path. A path or route is the part of the URL trailing after the first ‘/’. For example, in the following URL, http://localhost:8000/hello/TutorialsPoint the path or the route would be /hello/TutorialsPoint In FastAPI, such a path string is given as a parameter to the operation decorator. The operation here refers to the HTTP verb used by the browser to send the data. These operations include GET, PUT, etc. The operation decorator (for example, @app.get(“/”)) is immediately followed by a function that is executed when the specified URL is visited. In the below example − from fastapi import FastAPI app = FastAPI() @app.get(“/”) async def index(): return {“message”: “Hello World”} Here, (“/”) is the path, get is the operation, @app.get(“/”) is the path operation decorator, and the index() function just below it is termed as path operation function. Any of the following HTTP verbs can be used as operations. Sr.No. Method & Description 1 GET Sends data in unencrypted form to the server. Most common method. 2 HEAD Same as GET, but without the response body. 3 POST Used to send HTML form data to the server. Data received by the POST method is not cached by the server. 4 PUT Replaces all current representations of the target resource with the uploaded content. 5 DELETE Removes all current representations of the target resource given by a URL. The async keyword in the function’s definition tells FastAPI that it is to be run asynchronously i.e. without blocking the current thread of execution. However, a path operation function can be defined without the async prefix also. This decorated function returns a JSON response. Although it can return almost any of Python’s objects, it will be automatically converted to JSON. Further in this tutorial, we shall see how such a function returns Pydantic model objects. The URL’s endpoint or path can have one or more variable parameters. They can be accepted by using Python’s string formatting notation. In the above example URL http://localhost:8000/hello/TutorialsPoint, the last value may change in every client request. This variable parameter can be accepted in a variable as defined in the path and passed to the formal parameters defined in the function bound to the operation decorator. Example Add another path decorator with a variable parameter in the route, and bind hello() function to have name parameter. Modify the main.py as per the following. import uvicorn from fastapi import FastAPI app = FastAPI() @app.get(“/”) async def index(): return {“message”: “Hello World”} @app.get(“/hello/{name}”) async def hello(name): return {“name”: name} Start the Uvicorn server and visit http://localhost:8000/hello/Tutorialspoint URL. The browser shows the following JSON response. {“name”:”Tutorialspoint”} Change the variable path parameter to something else such as http://localhost:8000/hello/Python so that the browser shows − {“name”:”Python”} Check OpenAPI docs Now if we check the OpenAPI documentation by entering the URL as http://localhost:8000/docs, it will show two routes and their respective view functions. Click the try out button below /hello/{name} button and give Tutorialspoint as the value of the name parameter’s description and then click the Execute button. It will then show the Curl command, the request URL and the details of server’s response with response body and response headers. A route can have multiple parameters separated by “/” symbol. from fastapi import FastAPI app = FastAPI() @app.get(“/hello/{name}/{age}”) async def hello(name,age): return {“name”: name, “age”:age} In this case, /hello is the route, followed by two parameters put in curly brackets. If the URL given in the browser’s address bar is http://localhost:8000/hello/Ravi/20, The data of Ravi and 20 will be assigned to variables name and age respectively. The browser displays the following JSON response − {“name”:”Ravi”,”age”:”20″} Path Parameters with Types You can use Python’s type hints for the parameters of the function to be decorated. In this case, define name as str and age as int. @app.get(“/hello/{name}/{age}”) async def hello(name:str,age:int): return {“name”: name, “age”:age} This will result in the browser displaying an HTTP error message in the JSON response if the types don’t match. Try entering http://localhost:8000/hello/20/Ravi as the URL. The browser’s response will be as follows − { “detail”: [ { “loc”: [ “path”, “age” ], “msg”: “value is not a valid integer”, “type”: “type_error.integer” } ] } The reason is obvious as age being integer, can’t accept a string value. This will also be reflected in the Swagger UI (OpenAPI) documentation. Print Page Previous Next Advertisements ”;

FastAPI – IDE Support

FastAPI – IDE Support ”; Previous Next The Type Hinting feature of Python is most effectively used in almost all IDEs (Integrated Development Environments) such as PyCharm and VS Code to provide dynamic autocomplete features. Let us see how VS Code uses the type hints to provide autocomplete suggestions while writing a code. In the example below, a function named as sayhello with name as an argument has been defined. The function returns a string by concatenating “Hello” to the name parameter by adding a space in between. Additionally, it is required to ensure that the first letter of the name be in upper case. Python’s str class has a capitalize() method for the purpose, but if one doesn’t remember it while typing the code, one has to search for it elsewhere. If you give a dot after name, you expect the list of attributes but nothing is shown because Python doesn’t know what will be the runtime type of name variable. Here, type hint comes handy. Include str as the type of name in the function definition. Now when you press dot (.) after name, a drop down list of all string methods appears, from which the required method (in this case capitalize()) can be picked. It is also possible to use type hints with a user defined class. In the following example a rectangle class is defined with type hints for arguments to the __init__() constructor. class rectangle: def __init__(self, w:int, h:int) ->None: self.width=w self.height=h Following is a function that uses an object of above rectangle class as an argument. The type hint used in the declaration is the name of the class. def area(r:rectangle)->int: return r.width*r.height r1=rectangle(10,20) print (“area = “, area(r1)) In this case also, the IDE editor provides autocomplete support prompting list of the instance attributes. Following is a screenshot of PyCharm editor. FastAPI makes extensive use of the type hints. This feature is found everywhere, such as path parameters, query parameters, headers, bodies, dependencies, etc. as well as validating the data from the incoming request. The OpenAPI document generation also uses type hints. Print Page Previous Next Advertisements ”;

FastAPI – Parameter Validation

FastAPI – Parameter Validation ”; Previous Next It is possible to apply validation conditions on path parameters as well as query parameters of the URL. In order to apply the validation conditions on a path parameter, you need to import the Path class. In addition to the default value of the parameter, you can specify the maximum and minimum length in the case of a string parameter. from fastapi import FastAPI, Path app = FastAPI() @app.get(“/hello/{name}”) async def hello(name:str=Path(…,min_length=3, max_length=10)): return {“name”: name} If the browser’s URL contains the parameter with a length less than 3 or more than 10, as in (http://localhost:8000/hello/Tutorialspoint), there will be an appropriate error message such as − { “detail”: [ { “loc”: [ “path”, “name” ], “msg”: “ensure this value has at most 10 characters”, “type”: “value_error.any_str.max_length”, “ctx”: { “limit_value”: 10 } } ] } The OpenAPI docs also shows the validations applied − Validation rules can be applied on numeric parameters too, using the operators as given below − gt − greater than ge − greater than or equal lt − less than le − less than or equal Let us modify the above operation decorator to include age as a path parameter and apply the validations. from fastapi import FastAPI, Path app = FastAPI() @app.get(“/hello/{name}/{age}”) async def hello(*, name: str=Path(…,min_length=3 , max_length=10), age: int = Path(…, ge=1, le=100)): return {“name”: name, “age”:age} In this case, validation rules are applied for both the parameters name and age. If the URL entered is http://localhost:8000/hello/hi/110, then the JSON response shows following explanations for validation failure − { “detail”: [ { “loc”: [ “path”, “name” ], “msg”: “ensure this value has at least 3 characters”, “type”: “value_error.any_str.min_length”, “ctx”: { “limit_value”: 3 } }, { “loc”: [ “path”, “age” ], “msg”: “ensure this value is less than or equal to 100”, “type”: “value_error.number.not_le”, “ctx”: { “limit_value”: 100 } } ] } The swagger UI documentation also identifies the constraints. The query parameters can also have the validation rules applied to them. You have to specify them as the part of arguments of Query class constructor. Let us add a query parameter called percent in the above function and apply the validation rules as ge=0 (i.e., greater then equal to 0) and lt=100 (less than or equal to 100) from fastapi import FastAPI, Path, Query @app.get(“/hello/{name}/{age}”) async def hello(*, name: str=Path(…,min_length=3 , max_length=10), age: int = Path(…, ge=1, le=100), percent:float=Query(…, ge=0, le=100)): return {“name”: name, “age”:age} If the URL entered is http://localhost:8000/hello/Ravi/20?percent=79, then the browser displays following JSON response − {“name”:”Ravi”,”age”:20} FastAPI correctly identifies percent as a query parameter with validation conditions applied. It is reflected in the OpenAPI documentation as follows − While the client can send the path and query parameters to the API server using GET method, we need to apply POST method to send some binary data as a part of the HTTP request. This binary data may be in the form of an object of any Python class. It forms the request body. FastAPI uses Pydantic library for this purpose. Print Page Previous Next Advertisements ”;