Flutter + FastAPI 30天速成计划自用并实践-第5天
·
Day 5 详细学习计划:Markdown 支持与 CORS 配置
学习目标
- 为文章内容添加 Markdown 支持
- 配置 CORS 解决跨域问题
- 学习 API 测试方法
- 使用 Postman 或 Swagger UI 测试接口
知识点详解
1. Markdown 简介
概念:
- 轻量级标记语言
- 易于阅读和编写
- 可转换为有效的 XHTML 或 HTML 文档
常用语法:
- 标题:
# H1,## H2,### H3 - 粗体:
**粗体文本** - 斜体:
*斜体文本* - 列表:
- 项目1或1. 项目1 - 链接:
[链接文本](URL) - 图片:
 - 代码块:
代码
2. CORS (Cross-Origin Resource Sharing)
产生原因:
- 浏览器同源策略限制
- 前端(localhost:3000)和后端(localhost:8000)端口不同构成跨域
解决方法:
- 后端配置允许跨域请求
- 使用 FastAPI 的 CORSMiddleware
3. API 测试工具
Swagger UI:
- FastAPI 自带
- 访问
/docs查看 - 可在线测试接口
Postman:
- 功能强大的 API 测试工具
- 支持各种 HTTP 方法
- 可保存测试用例
- 创建项目目录
第一个 FastAPI 应用
创建 main.py 文件:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
运行应用:
uvicorn main:app --reload
写代码
一共三个文件:main.py, schemas.py, database.py
schemas.py
from sqlmodel import SQLModel, Field
from typing import Optional
from datetime import datetime
# 数据库模型和响应模型共用的基础模型
class ArticleBase(SQLModel):
title: str
content: str
author: Optional[str] = None
published: bool = False
# 数据库模型
class Article(ArticleBase, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
created_at: Optional[datetime] = None
# 创建文章时使用的模型
class ArticleCreate(ArticleBase):
pass
# 更新文章时使用的模型
class ArticleUpdate(ArticleBase):
title: Optional[str] = None
content: Optional[str] = None
# 数据库返回的文章模型
class ArticleRead(ArticleBase):
id: int
created_at: Optional[datetime] = None
database.py
from sqlmodel import SQLModel, create_engine, Field, Session
from typing import Optional
from datetime import datetime
# 数据库文件Url
DATABASE_URL = "sqlite:///./articles.db"
# 创建数据库引擎,echo=True表示打印SQL语句
engine = create_engine(DATABASE_URL, echo=True)
# 创建所有表
def create_db_and_tables():
SQLModel.metadata.create_all(engine)
# 获取数据库会话
def get_session():
with Session(engine) as session:
yield session #yield作用是返回一个迭代器,迭代器中的数据是yield后面的数据
main.py
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.responses import HTMLResponse
from fastapi.middleware.cors import CORSMiddleware
from sqlmodel import select, Session
from typing import List
from markdown import markdown
from database import create_db_and_tables, get_session, engine
from schemas import ArticleCreate, ArticleRead, ArticleUpdate, Article
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
# 应用启动时创建数据库表
create_db_and_tables()
yield
# 应用关闭时可以执行清理工作
app = FastAPI(lifespan=lifespan,title="Tutorial Site API", version="0.1.0")
# 添加cors中间件,允许所有来源访问API,方法和头部
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],# 在生产环境中应指定允许的来源
allow_credentials=True,# 允许cookie
allow_methods=["*"],
allow_headers=["*"],
)
# 创建文章接口
@app.post("/articles/", response_model=ArticleRead, status_code=status.HTTP_201_CREATED)
def create_article(*,
article: ArticleCreate,
session: Session = Depends(get_session)):
db_article = Article.from_orm(article)
session.add(db_article)
session.commit()
session.refresh(db_article)
return db_article
# 获取所有文章接口
@app.get("/articles/", response_model=List[ArticleRead])
def read_articles(*, session: Session = Depends(get_session)):
articles = session.exec(select(Article)).all()
return articles
# 获取单个文章接口
@app.get("/articles/{article_id}", response_model=ArticleRead)
def read_article(*, article_id: int, session: Session = Depends(get_session)):
article = session.get(Article, article_id)
if not article:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Article not found")
return article
# 获取文章 html 内容接口
# @app.get("/articles/{article_id}/html", response_model=dict)
@app.get("/articles/{article_id}/html", response_class=HTMLResponse)
def read_article_html(*, article_id: int, session: Session = Depends(get_session)):
article = session.get(Article, article_id)
if not article:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Article not found")
# 使用 markdown 库将 markdown 内容转换为 html
print('======================',article.content,'=============================')
html_content = markdown(article.content)
# return {"id": article.id, "title": article.title, "html": html_content}
return HTMLResponse(content=html_content)
# 更新文章接口
@app.put("/articles/{article_id}", response_model=ArticleRead)
def update_article(*,
article_id: int,
article_update: ArticleUpdate,
session: Session = Depends(get_session)):
article = session.get(Article, article_id)
if not article:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Article not found")
# 只更新提供的字段
article_data = article_update.dict(exclude_unset=True)
for key, value in article_data.items():
setattr(article, key, value)
session.add(article)
session.commit()
session.refresh(article)
return article
# 删除文章接口
@app.delete("/articles/{article_id}")
def delete_article(*,
session: Session = Depends(get_session),
article_id: int):
article = session.get(Article, article_id)
if not article:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Article not found")
session.delete(article)
session.commit()
return {"ok": True}
# 根目录欢迎信息
@app.get("/")
def read_root():
return {"message": "Welcome to the tutorial site API!"}
总结
使用 Postman 测试 API
我发现这个访问是个问题,于是找了替代的在线方案https://app.apifox.com/
1. 创建文章
- 方法:POST
- URL:http://localhost:8000/articles/
- Body 类型:JSON
- 内容:
{
"title": "使用 Postman 测试 API",
"content": "# Postman 教程\n\n## 简介\nPostman 是一个强大的 API 测试工具。\n\n## 使用步骤\n1. 打开 Postman\n2. 创建新请求\n3. 输入 URL 和方法\n4. 发送请求",
"author": "你的名字"
}
2. 获取文章列表
- 方法:GET
- URL:http://localhost:8000/articles/
3. 获取单篇文章
- 方法:GET
- URL:http://localhost:8000/articles/1
4. 获取文章 HTML 内容
- 方法:GET
- URL:http://localhost:8000/articles/1/html
在获取html的时候可以用网页访问,并且可以调整下面的代码可以方案到md文件的效果
# 获取文章 html 内容接口
# @app.get("/articles/{article_id}/html", response_model=dict)
@app.get("/articles/{article_id}/html", response_class=HTMLResponse)
def read_article_html(*, article_id: int, session: Session = Depends(get_session)):
article = session.get(Article, article_id)
if not article:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Article not found")
# 使用 markdown 库将 markdown 内容转换为 html
print('======================',article.content,'=============================')
html_content = markdown(article.content)
# return {"id": article.id, "title": article.title, "html": html_content}
return HTMLResponse(content=html_content)
今天学习了如何将markdown转换为html,并使用了https://app.apifox.com/进行接口测试,添加了跨域访问,但是没有验证。明天测试下。
更多推荐


所有评论(0)