FastAPI - Type Hints

FastAPI makes extensive use of the Type hinting feature made available in Python’s version 3.5 onwards. As a matter of fact, Python is known to be a dynamically typed language. It also happens to be Python’s distinct feature. In a Python code, a variable need not be declared to be belonging to a certain type, and its type is determined dynamically by the instantaneous value assigned to it. Python’s interpreter doesn’t perform type checks and hence it is prone to runtime exceptions.

In the following example, a division() function is defined with two parameters and returns their division, assuming that the parameters will be numeric.

>>> def division(a, b):
   return a/b
>>> division(10, 4)
>>> division(10, 2.5)

However, if one of the values passed to the function happen to be nonnumeric, it results in TypeError as shown below −

>>> division("Python",5)
TypeError: unsupported operand type(s) for /: 'str' and 'int'

Even a basic coding environment such as IDLE indicates that the function requires two parameters but won’t specify the types as they haven’t been declared.

FastAPI Type Hint

Python’s new type hinting feature helps in prompting the user with the expected type of the parameters to be passed. This is done by adding a colon and data type after the parameter. We’ll redefine the division() function as follows −

FastAPI Type Hint

Note that while calling the function, Python hints at the expected type of each parameter to be passed. However, this doesn’t prevent the TypeError from appearing if an incompatible value is passed. You will have to use a static type checker such as MyPy to check for compatibility before running.

Just as the formal parameters in the function’s definition, it is possible to provide type hint for a function’s return value. Just before the colon symbol in the function’s definition statement (after which the function block starts) add an arrow (->) and the type.

FastAPI Type Hint

However, as mentioned earlier, if incompatible values are passed to the function, or returned by the function, Python reports TypeError. Use of MyPy static type checker can detect such errors. Install mypy package first.

pip3 install mypy

Save the following code as

def division(x:int, y:int) -> int:
   return (x//y)
print (a)
print (b)
print (c)

Check this code for type errors using mypy.

C:\python37>mypy error: Argument 2 to "division" has incompatible
type "float"; expected "int" error: Argument 1 to "division" has
incompatible type "str"; expected "int"
Found 2 errors in 1 file (checked 1 source file)

There are errors in second and third calls to the function. In second, value passed to y is float when int is expected. In third, value passed to x is str when int is expected. (Note that // operator returns integer division)

All standard data types can be used as type hints. This can be done with global variables, variables as function parameters, inside function definition etc.

x: int = 3
y: float = 3.14
nm: str = 'abc'
married: bool = False
names: list = ['a', 'b', 'c']
marks: tuple = (10, 20, 30)
marklist: dict = {'a': 10, 'b': 20, 'c': 30}

A new addition in newer versions of Python (version 3.5 onwards) standard library is the typing module. It defines special types for corresponding standard collection types. The types on typing module are List, Tuple, Dict, and Sequence. It also consists of Union and Optional types. Note that standard names of data types are all in small case, whereas ones in typing module have first letter in upper case. Using this feature, we can ask a collection of a particular type.

from typing import List, Tuple, Dict
# following line declares a List object of strings.
# If violated, mypy shows error
cities: List[str] = ['Mumbai', 'Delhi', 'Chennai']
# This is Tuple with three elements respectively
# of str, int and float type)
employee: Tuple[str, int, float] = ('Ravi', 25, 35000)
# Similarly in the following Dict, the object key should be str
# and value should be of int type, failing which
# static type checker throws error
marklist: Dict[str, int] = {'Ravi': 61, 'Anil': 72}