Saturday, 28 August 2021

FastAPI

# for defining optional query parameters, we use Optional
# for defining the request body, we use BaseModel
# Get request only take path and query parameter (if you put body then it'll give an error)
# ex. https://something.com/path?query=value
# here path is path parameter and value is query


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

app = FastAPI()

class Item(BaseModel):
name: str
price: float
is_offer: Optional[bool] = None


@app.get("/")
def read_root():
return {'Hello': 'world'}


@app.get("/items/{item_id}")
def read_item(item_id:int, q:Optional[str]=None):
return {'item_id':item_id, 'query':q}


@app.put("/items/{item_id}")
def update_item(item_id:int, item:Item):
return {'item_name':item.name, 'item_id':item_id, 'item_price':item.price}


* like Optional, we can use from typing import Optional, List, Tuple, Set, Dict.
in the request body.

class Item(BaseModel):
name: str
price: float
info_type: List[str]
is_offer: Optional[bool] = None

--------------------------------------------------
Query -

from typing import Optional from fastapi import FastAPI, Query

app = FastAPI() @app.get("/items/") async def read_items( q: Optional[str] = Query( None, title="Query string", description="Query string for the items to search in the database that have a good match", min_length=3, regex="^fixedquery$", max_length=50, alias="item-query")): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) return results


So, when you need to declare a value as required while using Query, you can use ... as the first argument:

async def read_items(q: str = Query(..., min_length=3)):
---------------------------------------------------------------------

Enum

If we want to receive a valid path or query parameters then we should use Enum. In swagger, it gives the option to select path parameters

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


It works for Query parameter also but we cant use for body parameter.



-----------------------------------------------------
Path:
Same as the Query parameter, we have Path parameter
if we don't want to specify any argument in a specific order, then we have to use * in the front.
from fastapi import FastAPI, Path app = FastAPI() @app.get("/items/{item_id}") async def read_items(*, item_id: int = Path(..., title="The ID of the item to get"), q: str): results = {"item_id": item_id} if q: results.update({"q": q}) return results


We can add validations like gt, gr, lt, le in both Path and Query parameters.

------------------------------------------------------------------------
Body:
In the Fast API we can define two request body.
from typing import Optional
from fastapi import FastAPIfrom pydantic import BaseModel
app = FastAPI()

class Item(BaseModel):    name: str    description: Optional[str] = None    price: float    tax: Optional[float] = None

class User(BaseModel):    username: str    full_name: Optional[str] = None

@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User):
    results = {"item_id": item_id, "item": item, "user": user}    return results


In this case, two request bodies we have User and Item.
so we have to provide like this 

{
    "item": {
        "name": "Foo",
        "description": "The pretender",
        "price": 42.0,
        "tax": 3.2
    },
    "user": {
        "username": "dave",
        "full_name": "Dave Grohl"
    }
}


* we have to define body which takes only one key value then 

from typing import Optional

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


class User(BaseModel):
    username: str
    full_name: Optional[str] = None


@app.put("/items/{item_id}")
async def update_item(

    item_id: int, item: Item, user: User, importance: int = Body(...)):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    return results

We can use all validations like gt, lt, ge and le in the Body.

----------------------------------

using Body, we can add validations only for singular but how to add validation inside the body class
answer - using Field

from typing import Optional
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field


app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = Field(
        None, title="The description of the item", max_length=300, example="Foo"
    )
    price: float = Field(..., gt=0, description="The price must be greater than zero")
    tax: Optional[float] = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item = Body(..., embed=True)):
    results = {"item_id": item_id, "item": item}
    return results


using Field, we can add validation to individual key inside class.


--------------------------------------

Nested Body:

from typing import Optional, Set

from fastapi import FastAPI

from pydantic import BaseModel, HttpUrl


app = FastAPI()


class Image(BaseModel):

    url: HttpUrl

    name: str


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()
    image: Optional[Image] = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results



We can add specific validations like url

from pydantic import BaseModel, HttpUrl

---------------------------------------

we can add extra data types like int, float and List

like UUID, datetime.datetime, datetime.date, datetime.time, datetime.timedelta, frozenset, bytes, Decimal


from datetime import datetime, time, timedelta
from typing import Optional
from uuid import UUID
from fastapi import Body, FastAPI

app = FastAPI()

@app.put("/items/{item_id}")
async def read_items(item_id: UUID, start_datetime: Optional[datetime] = Body(None), end_datetime: Optional[datetime] = Body(None), 
    repeat_at: Optional[time] = Body(None), process_after: Optional[timedelta] = Body(None)):

    start_process = start_datetime + process_after
    duration = end_datetime - start_process
    return {"item_id": item_id, "start_datetime": start_datetime, "end_datetime": end_datetime, "repeat_at": repeat_at,
        "process_after": process_after, "start_process": start_process, "duration": duration }



Here Fast API expect body like
{
  "start_datetime": "2021-08-29T08:07:44.590Z",
  "end_datetime": "2021-08-29T08:07:44.590Z",
  "repeat_at": "string",
  "process_after": 0
}



Headers:

In the Get request, we use Headers along with the Path and Query parameters.
generally, Headers are hyphen separated but since we can't write variable name with hyphen in the python hence Fast API header automatically converts underscore separated into hyphen separated.

i.e. even if we write header as header_name it converts to header-name
we want to disable it then we can do convert_underscores=False


from typing import Optional
from fastapi import FastAPI, Header
app = FastAPI()

@app.get("/items/")
async def read_items(strange_header: Optional[str] = Header(None, convert_underscores=False)):
    return {"strange_header": strange_header}
 


if we want to call this api using python then 
requests.get('http://127.0.0.1:8000/items/', headers={'strange-header':'header_name'}).json()


---------------------------------------------------------

Response Model:

Sometimes, we want to send users a specific type of response. here response model comes to the rescue.

suppose, we are taking email, password and other details from users and in response want to send everything except the password.

--
from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()



class UserIn(BaseModel):

    username: str

    password: str

    email: EmailStr
    full_name: Optional[str] = None



class UserOut(BaseModel):

    username: str
    email: EmailStr
    full_name: Optional[str] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
    return user



** In the response model output, if we dont want to send default ones then we can use unset
@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)



** If we want to include or exclude something from the response model response

from typing import Optional from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: Optional[str] = None price: float tax: float = 10.5 items = { "foo": {"name": "Foo", "price": 50.2}, "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2}, "baz": { "name": "Baz", "description": "There goes my baz", "price": 50.2, "tax": 10.5, }, } @app.get( "/items/{item_id}/name", response_model=Item, response_model_include={"name", "description"}, ) async def read_item_name(item_id: str): return items[item_id] @app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"}) async def read_item_public_data(item_id: str): return items[item_id]


----------------------------------------------

Form Data:

When you need to receive form fields instead of JSON, you can use Form.

from fastapi import FastAPI, Form 
app = FastAPI() 

 @app.post("/login/") 
async def login(username: str = Form(...), password: str = Form(...)): 
     return {"username": username}



to call this request in the python:

requests.post('http://127.0.0.1:8000/login/', data=dict(username='username', password='password')).json()


------------------------------------------------------------------------------
read the file

from fastapi import FastAPI, File, UploadFile 
 app = FastAPI() 

@app.post("/files/") 
async def create_file(file: bytes = File(...)): 
     return {"file_size": len(file)} 


@app.post("/uploadfile/") 
async def create_upload_file(file: UploadFile = File(...)): 
     return {"filename": file.filename}


If you declare the type of your path operation function parameter as bytesFastAPI will read the file for you and you will receive the contents as bytes

Have in mind that this means that the whole contents will be stored in memory. This will work well for small files.

upload file:
A file stored in memory up to a maximum size limit, and after passing this limit it will be stored in disk

  • This means that it will work well for large files like images, videos, large binaries, etc. without consuming all the memory.


    Wednesday, 4 August 2021

    Git tutorial

     1. How to Push and commit.


    1. clone the repository to any folder: 

    git clone <copied url>


    2. if you have already cloned (some days before) and want to take the latest code in your local:

    git pull 


    3. if you have added some code in your local folder and want to push that to Github:

    1. git status: gives the status of a tracked file. i..e. which is pushed to GitHub, which are modified and which are untracked (new)

     2. git add <filename>  (if you want to push a specific file) (this moves the file to staging area)

    3. git add .             (if you want to push all the changes, here '.' represents all the files)

    4.  git commit -m "msg you want to type"  (this command move the file to the local .git) 

    5. git push origin <branch name>   (this command moves the file to GitHub) (origin is alias name of git URL)

    6. git remote add origin <URL of git repo> ( to add origin. now onwards origin is an alias of GitHub URL)


    -------------------------------------------------------------------------

    How to create a new repository:

    1. click on create a new repository in Github and create

    2. in the gitbash go to respective folder and type --- git init    (this will create .git folder in your local)

    3. git add <filename>

    4. git commit -m "your comment"

    5. git remote add origin <URL of git repo>

    6. git push origin <branch name>



    ----------------------------------------------------------------------------------------

    create new branch:

    1. to create branch from github website click on branch and type branch name which you want to create. in github you have to create a new branch from some old branch so that source file of old branch will be automatically there in the new branch

    2. for creating it through gitbash: git branch <branch name>

    by this way, you create the new branch but don't switch to this branch

    3. for switching it to a new branch.

    git checkout <branch name>

    4. for creating and switching it to the new branch

    git checkout -b <branch name>

    5. renaming the branch

    git branch -m <oldname>  <new name>

    6. renaming the current branch

    git branch -m <new name>