Tuesday 2 November 2021

FastAPI: Order matter while defining path parameter

Path operations are evaluated in the order they defined.  In case, if you have fixed paths in the path definitions, define them prior to the variable paths.

 

For example,

@app.get("/emps/by-id/self")
def self():
    return {'name' : 'Krishna', 'age' : 32}
    
@app.get("/emps/by-id/{empId}")
def empById(empId: int = Path(None, description = "Enter valid employee id", gt = 0, lt = 3)):
    if(empId in emps):
        return emps[empId]
    else:
        raise Exception("Employee not exist with given id " + str(empId))

 

As you see above snippet, I have a path ‘/emps/by-id/self’ to describe self, and ‘/emps/by-id/{empId}’ to get the data about an employee by id. Since path operations evaluate in order, you should make sure that the path for ‘/emps/by-id/self’ is declared before the one for ‘/emps/by-id/{empId}’.

 

Otherwise empId is matched to the value ‘self’ and you will get below validation error.

 

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

 

Find the below working application.

 

main.py

from fastapi import FastAPI, Path
from typing import Optional
from pydantic import BaseModel

app = FastAPI()

# model classes
class Employee(BaseModel):
    name: str
    age: int

class EmployeeUpdateDto(BaseModel):
    name: Optional[str]
    age : Optional[int]

# employees information
emps = {
    1 : {
        "name" : "Krishna",
        "age": 32
    },
    2 : {
        "name" : "Ram",
        "age": 33
    }
}

# Create home endpoint
@app.get("/")
def home():
    return {"name" : "Hello World app", "version": "2.0.0"}

# Employees REST APIs
@app.get("/emps")
def allEmployees():
    return emps

@app.get("/emps/by-id/self")
def self():
    return {'name' : 'Krishna', 'age' : 32}
    
@app.get("/emps/by-id/{empId}")
def empById(empId: int = Path(None, description = "Enter valid employee id", gt = 0, lt = 3)):
    if(empId in emps):
        return emps[empId]
    else:
        raise Exception("Employee not exist with given id " + str(empId))

@app.get("/emps/by-name")
def empByName(name: Optional[str] = None):
    if name == None:
        return {"message" : "no input provided"}
    for empId in emps:
        if emps[empId]["name"] == name:
            return emps[empId]
    return {"message" : "Not found"}

@app.post("/emps")
def createEmployee(emp: Employee):
    noOfEmps = len(emps)
    newId = noOfEmps + 1
    emps[newId] = emp
    return {"id" : newId, "name" : emp.name, "age": emp.age}

@app.put("/emps/by-id/{empId}")
def updateEmployee(empId : int, emp: EmployeeUpdateDto):
    if(empId not in emps):
        return {"message" : "Not found"}
    
    persistedEmp = emps[empId]

    if(emp.name != None):
        persistedEmp["name"] = emp.name
    
    if(emp.age != None):
        persistedEmp["age"] = emp.age

    return {"id" : empId, "name" : persistedEmp["name"], "age": persistedEmp["age"]}

@app.delete("/emps/by-id/{empId}")
def deleteEmpById(empId: int = Path(None, description = "Enter valid employee id")):
    if(empId in emps):
        del emps[empId]
        return {"msg" : "Employee is deleted with given id " + str(empId)}
    else:
        return {"msg" : "Employee not exist with given id " + str(empId)}

 

Open terminal and execute the command ‘uvicorn main:app --reload'.

$uvicorn main:app --reload
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [97482] using statreload
INFO:     Started server process [97499]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

Open the url ‘http://127.0.0.1:8000/emps/by-id/self’ in browser, you will see below kind of output.



Open the url ‘http://127.0.0.1:8000/emps/by-id/2’ in browser, you will see below screen.

 


 

 

 

Previous                                                    Next                                                    Home

No comments:

Post a Comment