FastAPI 101

 

HST PF

自從轉成全職後端也已經快年了

現在的主要工作是寫Django

每天兢兢業業工作

偶爾寫寫Flask接案或project

那為什麼不都用Django寫?

Django

$ django-admin startproject steven5538

Flask

Django

$ django-admin startproject steven5538

$ cd steven5538

Flask

Django

$ django-admin startproject steven5538

$ cd steven5538

$ django-admin startapp FuckWorld 

Flask

Django

$ django-admin startproject steven5538

$ cd steven5538

$ django-admin startapp FuckWorld

$ tree

Flask

Django

$ django-admin startproject steven5538

$ cd steven5538

$ django-admin startapp FuckWorld

$ tree

|-- FuckWorld
|   |-- __init__.py
|   |-- settings.py
|   |-- urls.py
|   `-- wsgi.py
`-- manage.py

Flask

Django

$ django-admin startproject steven5538

$ cd steven5538

$ django-admin startapp FuckWorld

$ tree

|-- FuckWorld
|   |-- __init__.py
|   |-- settings.py
|   |-- urls.py
|   `-- wsgi.py
`-- manage.py

$ cd FuckWorld; vim urls.py view.py; cd ..

Flask

Django

$ django-admin startproject steven5538

$ cd steven5538

$ django-admin startapp FuckWorld

$ tree

|-- FuckWorld
|   |-- __init__.py
|   |-- settings.py
|   |-- urls.py
|   `-- wsgi.py
`-- manage.py

$ cd FuckWorld; vim urls.py view.py; cd ..

$ python manager.py runserver 0.0.0.0:5538

Flask

Django

$ django-admin startproject steven5538

$ cd steven5538

$ django-admin startapp FuckWorld

$ tree

|-- FuckWorld
|   |-- __init__.py
|   |-- settings.py
|   |-- urls.py
|   `-- wsgi.py
`-- manage.py

$ cd FuckWorld; vim urls.py view.py; cd ..

$ python manager.py runserver 0.0.0.0:5538

Flask

$ vim steven5538.py

 

Django

$ django-admin startproject steven5538

$ cd steven5538

$ django-admin startapp FuckWorld

$ tree

|-- FuckWorld
|   |-- __init__.py
|   |-- settings.py
|   |-- urls.py
|   `-- wsgi.py
`-- manage.py

$ cd FuckWorld; vim urls.py view.py; cd ..

$ python manager.py runserver 0.0.0.0:5538

Flask

$ vim steven5538.py

$ python steven5538.py

 

來寫個傳統的Flask網頁

Steven5538.py

from flask import Flask, render_template

app = Flask()

@app.route('/index')
def index():
    return render_template('index.html', name='steven5538')

index.html

<html>
	<h1>Hello, {{name}}</h1>
</html>

但現在目前主流架構

都是分離

端工程師再也不用理端的扣了

我們只要注意自己的API
剩下的都是端的鍋 (

來看個FlaskAPI

Steven5538.py

from flask import Flask, request

app = Flask(__name__)

@app.route('/hacker', methods=['GET'])
def get_hacker():
    info = request.json
    name = info['name']
    age = int(info['age']) 
    msg = f'駭客名字是:{name}'
    return {'success': True, 'msg': msg, 'age':age}
import requests
data = requests.get('http://127.0.0.1:5538/hacker?name=steven5538&age=18').json()
print(data)

{ 'success': True, 'msg': '駭客名字是:steven5538', 'age': 18 }

唷, 看起來不錯喔

Steven5538.py

from flask import Flask, request

app = Flask(__name__)

@app.route('/hacker', methods=['GET'])
def get_hacker():
    info = request.json
    name = info['name']
    age = int(info['age']) 
    msg = f'駭客名字是:{name}'
    return {'success': True, 'msg': msg, 'age':age}
import requests
data = requests.get('http://127.0.0.1:5538/hacker?name=steven5538&age=十八').json()
print(data)

Steven5538.py

from flask import Flask, request

app = Flask(__name__)

@app.route('/hacker', methods=['GET'])
def get_hacker():
    info = request.json
    name = info['name']
    age = int(info['age']) 
    msg = f'駭客名字是:{name}'
    return {'success': True, 'msg': msg, 'age':age}
import requests
data = requests.get('http://127.0.0.1:5538/hacker?name=steven5538&age=十八').json()
print(data)

ValueError !!

哈Fix

Steven5538.py

from flask import Flask, request

app = Flask(__name__)

@app.route('/hacker', methods=['GET'])
def get_hacker():
    info = request.json
    name = info['name']
    if not info['age'].isdigit():
    	return {'success': False, 'msg': '年齡必需整數'}
    age = int(info['age'])
    msg = f'駭客名字是:{name}'
    return {'success': True, 'msg': msg, 'age':age}
import requests
data = requests.get('http://127.0.0.1:5538/hacker?name=steven5538&age=十八').json()
print(data)

{'success': False, 'msg': '年齡必需整數'}

Steven5538.py

import requests
data = requests.get('http://127.0.0.1:5538/hacker?age=18').json()
print(data)
from flask import Flask, request

app = Flask(__name__)

@app.route('/hacker', methods=['GET'])
def get_hacker():
    info = request.json
    name = info['name']
    if not info['age'].isdigit():
    	return {'success': False, 'msg': '年齡必需整數'}
    age = int(info['age'])
    msg = f'駭客名字是:{name}'
    return {'success': True, 'msg': msg, 'age':age}

Steven5538.py

import requests
data = requests.get('http://127.0.0.1:5538/hacker?age=18').json()
print(data)
from flask import Flask, request

app = Flask(__name__)

@app.route('/hacker', methods=['GET'])
def get_hacker():
    info = request.json
    name = info['name']
    if not info['age'].isdigit():
    	return {'success': False, 'msg': '年齡必需整數'}
    age = int(info['age'])
    msg = f'駭客名字是:{name}'
    return {'success': True, 'msg': msg, 'age':age}

KeyError !!

哈Fix

Steven5538.py

import requests
data = requests.get('http://127.0.0.1:5538/hacker?age=18').json()
print(data)

{'success': False, 'msg': '姓名不可為空'}
from flask import Flask, request

app = Flask(__name__)

@app.route('/hacker', methods=['GET'])
def get_hacker():
    info = request.json
    name = info.get('name', '')
    if not name:
        return {'success': False, 'msg': '姓名不可為空'}
    if not info['age'].isdigit():
    	return {'success': False, 'msg': '年齡必需整數'}
    age = int(info['age'])
    msg = f'駭客名字是:{name}'
    return {'success': True, 'msg': msg, 'age':age}

然後再來個300個endpoints

看來是可以開始準備退休生活了

但是為了明天的飯錢著想

還是要找個方法解決

終於在最近看到個好東西

Steven5538.py - by FastAPI

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Hacker(BaseModel):
    name: str
    age: int
    
@app.get('/hacker')
def get_hacker(hacker: Hacker):
    return {'success': True, 'msg': f'駭客名字是:{hacker.name}', 'age':hacker.age}
import requests
data = requests.get('http://127.0.0.1:5538/hacker?name=steven5538&age=18').json()
print(data)

{ 'success': True, 'msg': '駭客名字是:steven5538', 'age': 18 }

Steven5538.py - by FastAPI

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Hacker(BaseModel):
    name: str
    age: int
    
@app.get('/hacker')
def get_hacker(hacker: Hacker):
    return {'success': True, 'msg': f'駭客名字是:{hacker.name}', 'age':hacker.age}
import requests
data = requests.get('http://127.0.0.1:5538/hacker?name=steven5538&age=十八').json()
print(data)

{'detail': [{'loc': ['body','hacker', 'age'],
	'msg':'value is not a valid integer',
	'type':'type_error.integer'}]}

Steven5538.py - by FastAPI

import requests
data = requests.get('http://127.0.0.1:5538/hacker?age=18').json()
print(data)

{'detail': [{'loc': ['body','hacker', 'name'],
	'msg':'filed required',
	'type':'value_error.missing'}]}
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Hacker(BaseModel):
    name: str
    age: int
    
@app.get('/hacker')
def get_hacker(hacker: Hacker):
    return {'success': True, 'msg': f'駭客名字是:{hacker.name}', 'age':hacker.age}

更多栗子

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

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

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

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

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

更多栗子

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"}

更多栗子

from fastapi import FastAPI
from pydantic import BaseModel

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

app = FastAPI()

@app.post("/items/")
async def create_item(item: Item):
    return item
<input>
{
    "name": "Foo",
    "description": "An optional description",
    "price": 45.2,
    "tax": 3.5
}

<output>
{
    "name": "Foo",
    "price": 45.2
}

更多栗子

from fastapi import Cookie, FastAPI

app = FastAPI()

@app.get("/items/")
async def read_items(*, ads_id: str = Cookie(None)):
    return {"ads_id": ads_id}
from fastapi import FastAPI, Header

app = FastAPI()

@app.get("/items/")
async def read_items(*, user_agent: str = Header(None)):
    return {"User-Agent": user_agent}
from fastapi import FastAPI, Form

app = FastAPI()

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

更多栗子

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()

class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str = None

class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str = None

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

更多栗子

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}

更多栗子

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"

engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

更多栗子

from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship

from .database import Base

class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    email = Column(String, unique=True, index=True)
    hashed_password = Column(String)
    is_active = Column(Boolean, default=True)

    items = relationship("Item", back_populates="owner")

class Item(Base):
    __tablename__ = "items"

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String, index=True)
    description = Column(String, index=True)
    owner_id = Column(Integer, ForeignKey("users.id"))

    owner = relationship("User", back_populates="items")

更多栗子

from fastapi import BackgroundTasks, FastAPI

app = FastAPI()

def write_notification(email: str, message=""):
    with open("log.txt", mode="w") as email_file:
        content = f"notification for {email}: {message}"
        email_file.write(content)

@app.post("/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
    background_tasks.add_task(write_notification, email, message="some notification")
    return {"message": "Notification sent in the background"}

更多栗子

End Page

Made with Slides.com