<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Web API &#8211; 李辉 / Grey Li</title>
	<atom:link href="https://greyli.com/tag/web-api/feed/" rel="self" type="application/rss+xml" />
	<link>https://greyli.com</link>
	<description>一个编程和写作爱好者的在线记事本</description>
	<lastBuildDate>Thu, 06 Nov 2025 11:36:11 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.9.26</generator>

<image>
	<url>https://greyli.com/wp-content/uploads/2025/03/avatar-500-compressed-144x144.jpg</url>
	<title>Web API &#8211; 李辉 / Grey Li</title>
	<link>https://greyli.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>APIFlask：一个基于 Flask 的 Web API 框架</title>
		<link>https://greyli.com/hello-apiflask/</link>
		<comments>https://greyli.com/hello-apiflask/#comments</comments>
		<pubDate>Thu, 01 Apr 2021 13:35:30 +0000</pubDate>
		<dc:creator><![CDATA[李辉]]></dc:creator>
				<category><![CDATA[计算机与编程]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[APIFlask]]></category>
		<category><![CDATA[FastAPI]]></category>
		<category><![CDATA[Flask]]></category>
		<category><![CDATA[REST API]]></category>
		<category><![CDATA[Web API]]></category>

		<guid isPermaLink="false">https://greyli.com/?p=3643</guid>
		<description><![CDATA[经常看到有人把 FastAPI 和 Flask 放到一起比较，但是却没有意识到这完全是两种东西——前者是基于  [&#8230;]]]></description>
				<content:encoded><![CDATA[<p class="md-end-block md-p"><span class="md-plain">经常看到有人把 FastAPI 和 Flask 放到一起比较，但是却没有意识到这完全是两种东西——前者是基于 Web 框架 Starlette 添加了 Web API 功能支持的（框架之上的）框架，而后者是和 Starlette 同类的通用 Web 框架。你怎么能让小明和骑电动车的小军赛跑然后还夸小军好快好强？为了让框架 PK 爱好者们有一个更公平的比较对象，从一份 </span><span class="md-meta-i-c  md-link"><a spellcheck="false" href="https://github.com/miguelgrinberg/APIFairy"><span class="md-plain">APIFairy</span></a></span><span class="md-plain"> 0.6.2 版本的 fork 开始，我实现了一个基于 Flask 的 Web API 框架——</span><span class="md-meta-i-c  md-link"><a spellcheck="false" href="https://github.com/greyli/apiflask"><span class="md-plain">APIFlask</span></a></span><span class="md-plain">：</span></p>
<p><img class="alignnone size-large" src="https://apiflask.com/_assets/apiflask-logo.png" width="2000" height="728" /></p>
<ul>
<li class="md-end-block md-p"><span class="md-plain">主页: </span><span class="md-meta-i-c md-link"><a spellcheck="false" href="https://apiflask.com/"><span class="md-plain">https://apiflask.com</span></a></span></li>
<li class="md-end-block md-p"><span class="md-plain">GitHub: </span><span class="md-link md-pair-s" spellcheck="false"><a href="https://github.com/greyli/apiflask">https://github.com/greyli/apiflask</a></span></li>
<li class="md-end-block md-p"><span class="md-plain">Twitter: </span><span class="md-link md-pair-s" spellcheck="false"><a href="https://twitter.com/apiflask">https://twitter.com/apiflask</a></span></li>
</ul>
<p class="md-end-block md-p"><span class="md-plain">APIFlask 在 Flask 的基础上添加了更多 Web API 相关的功能支持，核心特性包括：</span></p>
<ul>
<li class="md-end-block md-p"><span class="md-plain">更多方便的装饰器，比如 </span><span class="md-pair-s" spellcheck="false"><code>@app.input()</code></span><span class="md-plain">、</span><span class="md-pair-s" spellcheck="false"><code>@app.output()</code></span><span class="md-plain">、</span><span class="md-pair-s" spellcheck="false"><code>@app.get()</code></span><span class="md-plain">、</span><span class="md-pair-s" spellcheck="false"><code>@app.post()</code></span><span class="md-plain"> 等等</span></li>
<li class="md-end-block md-p"><span class="md-plain">自动反序列化和验证请求格式，当请求数据不符合模式类要求时，会自动生成包含错误详细信息的错误响应（基于 </span><span class="md-meta-i-c  md-link"><a spellcheck="false" href="https://github.com/marshmallow-code/webargs"><span class="md-plain">Webargs</span></a></span><span class="md-plain">）</span></li>
<li class="md-end-block md-p"><span class="md-plain">自动格式化和序列化响应数据，在定义好响应模式后，你可以直接在视图函数返回一个模型类对象，或是返回字典（基于 </span><span class="md-meta-i-c  md-link"><a spellcheck="false" href="https://github.com/marshmallow-code/marshmallow"><span class="md-plain">Marshmallow</span></a></span><span class="md-plain">）</span></li>
<li class="md-end-block md-p"><span class="md-plain">自动生成 </span><span class="md-meta-i-c  md-link"><a spellcheck="false" href="https://github.com/OAI/OpenAPI-Specification"><span class="md-plain">OpenAPI Specification</span></a></span><span class="md-plain"> 文件，你可以把这个文件导入到 API 调试工具或是用来生成客户端代码（基于 </span><span class="md-meta-i-c  md-link"><a spellcheck="false" href="https://github.com/marshmallow-code/apispec"><span class="md-plain">APISpec</span></a></span><span class="md-plain">）</span></li>
<li class="md-end-block md-p"><span class="md-plain">自动生成交互式 API 文档，并自动为蓝本和视图设置对应的标签分类（基于 </span><span class="md-meta-i-c  md-link"><a spellcheck="false" href="https://github.com/swagger-api/swagger-ui"><span class="md-plain">Swagger UI</span></a></span><span class="md-plain"> and </span><span class="md-meta-i-c  md-link"><a spellcheck="false" href="https://github.com/Redocly/redoc"><span class="md-plain">Redoc</span></a></span><span class="md-plain">）</span></li>
<li class="md-end-block md-p"><span class="md-plain">自动为 HTTP 错误生成 JSON 格式的错误响应</span></li>
</ul>
<p class="md-end-block md-p"><span class="md-plain">下面是一个最基础的示例程序：</span></p>
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded " lang="" spellcheck="false"> from apiflask import APIFlask, Schema, abort
 from apiflask.fields import Integer, String
 from apiflask.validators import Length, OneOf
 ​
 app = APIFlask(__name__)  # 可以使用 title 和 version 参数来自定义 API 的名称和版本
 ​
 pets = [
     {
         'id': 0,
         'name': 'Kitty',
         'category': 'cat'
     },
     {
         'id': 1,
         'name': 'Coco',
         'category': 'dog'
     }
 ]
 ​
 # 定义一个请求数据模式类
 class PetInSchema(Schema):
     name = String(required=True, validate=Length(0, 10))  # 可以使用 description 参数添加字段描述
     category = String(required=True, validate=OneOf(['dog', 'cat']))
 ​
 # 定义一个响应数据模式类
 class PetOutSchema(Schema):
     id = Integer()
     name = String()
     category = String()
 ​
 ​
 @app.get('/pets/&lt;int:pet_id&gt;')
 @app.output(PetOutSchema)  # 使用 @output 装饰器标记响应数据模式
 def get_pet(pet_id):
     if pet_id &gt; len(pets) - 1:
         abort(404)
     # 在真实程序里，你可以直接返回 ORM 模型类的实例，比如
     # return Pet.query.get(1)
     return pets[pet_id]
 ​
 ​
@app.patch('/pets/&lt;int:pet_id&gt;')
@app.input(PetInSchema(partial=True))  # 使用 @input 装饰器标记请求数据模式
@app.output(PetOutSchema)
def update_pet(pet_id, json_data):  # 通过验证后的请求数据字典会注入到视图函数，默认参数名为 json_data
    if pet_id &gt; len(pets) - 1:
        abort(404)
    for attr, value in json_data.items():
        pets[pet_id][attr] = value
    return pets[pet_id]</pre>
<p>P.S. 你也可以使用类视图（class-based views），具体示例见<a href="https://github.com/greyli/apiflask/blob/master/examples/cbv/app.py">这里</a>。</p>
<p class="md-end-block md-p"><span class="md-plain">如果你想在你的电脑上运行这个示例，可以先用下面的命令安装 APIFlask（需要 Python 3.7 及以上版本，Flask 1.1 及以上版本）：</span></p>
<p class="md-end-block md-p"><span class="md-plain">Linux 和 macOS:</span></p>
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="" spellcheck="false"> $ pip3 install apiflask</pre>
<p class="md-end-block md-p"><span class="md-plain">Windows:</span></p>
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="" spellcheck="false"> &gt; pip install apiflask</pre>
<p class="md-end-block md-p"><span class="md-plain">安装完成后把上面的代码保存到文件 </span><span class="md-pair-s" spellcheck="false"><code>app.py</code></span><span class="md-plain">，然后执行下面的命令运行程序：</span></p>
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="" spellcheck="false"> $ flask run</pre>
<p class="md-end-block md-p"><span class="md-plain">现在你可以在浏览器访问 </span><span class="md-link md-pair-s" spellcheck="false"><a href="http://localhost:5000/docs">http://localhost:5000/docs</a></span><span class="md-plain"> 查看基于 Swagger UI 自动生成的交互式 API 文档：</span></p>
<p><img class="alignnone size-large" src="https://apiflask.com/_assets/swagger-ui.png" alt="Swagger UI" width="1681" height="1918" /></p>
<p class="md-end-block md-p"><span class="md-plain">或者访问 </span><span class="md-link md-pair-s" spellcheck="false"><a href="http://localhost:5000/redoc">http://localhost:5000/redoc</a></span><span class="md-plain"> 查看基于 Redoc 生成的 API 文档：</span></p>
<p><img class="alignnone size-large" src="https://apiflask.com/_assets/redoc.png" alt="Redoc" width="1681" height="1918" /></p>
<p class="md-end-block md-p"><span class="md-plain">访问 </span><span class="md-link md-pair-s" spellcheck="false"><a href="http://localhost:5000/openapi.json">http://localhost:5000/openapi.json</a></span><span class="md-plain"> 可以获取自动生成的 OpenAPI spec 文件。</span></p>
<p class="md-end-block md-p"><span class="md-plain">这个示例程序的完整版本可以在 </span><span class="md-link md-pair-s" spellcheck="false"><a href="https://github.com/greyli/apiflask/tree/master/examples">https://github.com/greyli/apiflask/tree/master/examples</a></span><span class="md-plain"> 看到。如果你想了解更多用法，可以阅读文档中的</span><span class="md-meta-i-c md-link"><a spellcheck="false" href="https://apiflask.com/usage"><span class="md-plain">基本用法</span></a></span><span class="md-plain">一章（目前只有英文）。</span></p>
<p class="md-end-block md-p md-focus"><span class="md-plain md-expand">APIFlask 只在 Flask 之上做了轻量级包装，所以你实际上仍然是在写一个 Flask 程序，所有 Flask 的特性都完全兼容。你只需要记住下面两处不同点：</span></p>
<ul>
<li class="md-end-block md-p"><span class="md-plain">创建程序实例的时候使用 </span><span class="md-pair-s" spellcheck="false"><code>APIFlask</code></span><span class="md-plain"> 类（</span><span class="md-pair-s" spellcheck="false"><code>from apiflask import APIFlask</code></span><span class="md-plain">）。</span></li>
<li class="md-end-block md-p"><span class="md-plain">创建蓝本实例的时候使用 </span><span class="md-pair-s" spellcheck="false"><code>APIBlueprint</code></span><span class="md-plain"> 类（</span><span class="md-pair-s" spellcheck="false"><code>from apiflask import APIBlueprint</code></span><span class="md-plain">）。</span></li>
<li>使用 <code>apiflask.abort()</code> 函数返回 JSON 格式的错误响应。</li>
</ul>
<p class="md-end-block md-p"><span class="md-plain">以下面的 Flask 程序为例：</span></p>
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="" spellcheck="false"> from flask import Flask, request, escape
 ​
 app = Flask(__name__)
 ​
 @app.route('/')
 def hello():
     name = request.args.get('name', 'Human')
     return f'Hello, {escape(name)}'</pre>
<p class="md-end-block md-p"><span class="md-plain">迁移到 APIFlask 只需要改动两行代码：</span></p>
<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="" spellcheck="false"> from apiflask import APIFlask  # 第一行
 from flask import request, escape
 ​
 app = APIFlask(__name__)  # 第二行
 ​
 @app.route('/')
 def hello():
     name = request.args.get('name', 'Human')
     return f'Hello, {escape(name)}'</pre>
<p class="md-end-block md-p"><span class="md-plain">欢迎提出改进建议，报告 bug 或是分享其他任何相关的想法。你也可以在 </span><span class="md-meta-i-c  md-link"><a spellcheck="false" href="https://github.com/greyli/apiflask"><span class="md-plain">GitHub</span></a></span><span class="md-plain md-expand"> 上创建 Issue，或是提交 PR 来改进它。谢谢！</span></p>
]]></content:encoded>
			<wfw:commentRss>https://greyli.com/hello-apiflask/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>开始写作第二本 Flask 书</title>
		<link>https://greyli.com/writing-another-flask-book/</link>
		<comments>https://greyli.com/writing-another-flask-book/#comments</comments>
		<pubDate>Sun, 28 Jul 2019 03:55:38 +0000</pubDate>
		<dc:creator><![CDATA[李辉]]></dc:creator>
				<category><![CDATA[计算机与编程]]></category>
		<category><![CDATA[Flask]]></category>
		<category><![CDATA[Web API]]></category>
		<category><![CDATA[写作]]></category>

		<guid isPermaLink="false">http://greyli.com/?p=2501</guid>
		<description><![CDATA[把自己的目标公之于众，有可能会因为受到监督而更容易完成目标，也有可能会让你潜意识里感觉自己好像已经完成了目标， [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>把自己的目标公之于众，有可能会因为受到监督而更容易完成目标，也有可能会让你潜意识里感觉自己好像已经完成了目标，从而让计划更难执行。我更相信前一种理论，所以决定现在公布第二本 Flask 书的写作计划。</p>
<h2>为什么要再写一本 Flask 书？</h2>
<p>尽管我很想早一点深入学习更多的东西，而不是局限在 Flask（或 Python） 领域，但事实是，在这一个领域就已经有太多的东西需要研究和学习……目前来说，我最想解决的就是 Web API 的编写问题。《Flask Web 开发实战》虽然在第十章介绍了 Web API 的大部分基础概念，但是只实现了一种 OAuth 认证流程，也没能深入更多内容，包括数据校验、请求封装等。因此，我决定再写一本书来覆盖这个主题。</p>
<p>另一个原因是，我在上一本书的电商页面、豆瓣条目还有其他地方收集到了一些批评，其中有一些很中肯，所以我想写一本更好的 Flask 书。除了克服这些批评里提到的缺点，我也会尝试更科学的写作方式，不会像上一本书那样在早期印刷版本包含那么多的笔误和疏漏。</p>
<p>作为试水，我在 PyCon China 2019 上海场会有一个相关主题的演讲：《<a href="http://greyli.com/pycon-china-2019-building-rest-api-with-flask/">基于 Flask 的 Web API 开发指南</a>》，如果你感兴趣的话，可以考虑<a href="https://www.bagevent.com/event/5293611">报名参加</a>。</p>
<h2>新书会包含哪些内容？</h2>
<p>不同于《Flask Web 开发实战》所追求的大而全，这本书的定位是一个小而精的 Flask 书。它会包含下面这几部分：</p>
<ul>
<li class="Editable-styled public-DraftStyleDefault-unorderedListItem public-DraftStyleDefault-reset public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR" data-block="true" data-editor="9ailo" data-offset-key="7ie5-0-0">
<div class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr" data-offset-key="7ie5-0-0"><span data-offset-key="7ie5-0-0"><span data-text="true">一个更轻松简单的入门部分。</span></span></div>
</li>
<li class="Editable-styled public-DraftStyleDefault-unorderedListItem public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR" data-block="true" data-editor="9ailo" data-offset-key="dtame-0-0">
<div class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr" data-offset-key="dtame-0-0"><span data-offset-key="dtame-0-0"><span data-text="true">进阶部分：开发一个传统 Web 程序。</span></span></div>
</li>
<li class="Editable-styled public-DraftStyleDefault-unorderedListItem public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR" data-block="true" data-editor="9ailo" data-offset-key="bd42c-0-0">
<div class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr" data-offset-key="bd42c-0-0"><span data-offset-key="bd42c-0-0"><span data-text="true">作为重点的 Web API 开发部分。</span></span></div>
</li>
<li class="Editable-styled public-DraftStyleDefault-unorderedListItem public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR" data-block="true" data-editor="9ailo" data-offset-key="4ojrg-0-0">
<div class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr" data-offset-key="4ojrg-0-0"><span data-offset-key="4ojrg-0-0"><span data-text="true">Flask 相关的进阶部分，包括缓存、异步任务、容器部署等。</span></span></div>
</li>
<li class="Editable-styled public-DraftStyleDefault-unorderedListItem public-DraftStyleDefault-depth0 public-DraftStyleDefault-listLTR" data-block="true" data-editor="9ailo" data-offset-key="491ah-0-0">
<div class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr" data-offset-key="491ah-0-0"><span data-offset-key="491ah-0-0"><span data-text="true">可能会加入的其他内容：FastAPI、Django REST Framework、GraphQL。</span></span></div>
</li>
</ul>
<p>这本书一来可以衔接《<a href="http://helloflask.com/tutorial">Flask 入门教程</a>》，二来可以补充《<a href="https://hellolflask.com/book">Flask Web 开发实战</a>》没有覆盖的内容。当然，对于学习 Flask，囊括几乎所有相关主题的《Flask Web 开发实战》仍然是一个不错的选择。</p>
<p>对于相同的主题，我会考虑使用不同的工具，比如《Flask Web 开发实战》里单元测试使用 unitttest，那么这本书就会介绍用 pytest；上一本书里编辑器介绍使用 PyCharm，这一本书或许就会介绍使用 VSCode。</p>
<p>下面是这本书的其他具体设计：</p>
<ul>
<li>只使用一个示例程序，贯穿全书。</li>
<li>使用中文作为示例程序的界面语言。</li>
<li>使用 Python3，但在书中对 Python2 兼容部分添加必要的提示。</li>
<li>对书中的代码块添加尽可能多的注释。</li>
<li>添加一个「术语表」，收集所有 Flask 和 Web 开发相关的术语，尝试给它们下一个简单易懂的定义。</li>
<li>添加一个「常见错误速查表」，列出常见错误、错误解释和对应的解决方法（在维护上一本书的时间里，我处理了大量提问，见识过各种错误和误区）。</li>
</ul>
<p>作为后续，在这本书完成后，我计划写一本电子书来介绍如何使用 Vue.js 基于这本 Flask 书编写的 Web API 来开发客户端。尽管我现在还没入门 Vue.js……但是我已经把放相关内容的网站域名准备好了：<a href="http://HelloVuejs.com">HelloVuejs.com</a>（它和 <a href="http://HelloFlask.com">HelloFlask.com</a> 是兄弟域名 :p）</p>
<h2>什么时间能完成？</h2>
<p>预计的发售时间是明年愚人节，即 2020 年 4 月 1 日。因为 Flask 的诞生时间是 2010 年的愚人节，所以明年愚人节会是 Flask 诞生十周年纪念日，一个很完美的发售时间。</p>
<p>如果你对这本书感兴趣，可以关注我的<a href="/wechat#gh">微信公众号</a>、<a href="https://twitter.com/greylihui">Twitter</a> 和<a href="https://douban.com/people/greyli">豆瓣</a>账号获取最新动态，或是访问这本书的<a href="http://helloflask.com/book/2/">主页</a>。</p>
<p>2020/4/1 更新：<a href="http://greyli.com/new-flask-book-delay/">Flask 新书完成时间推迟</a></p>
<h2>你想看到什么内容？</h2>
<p>在公开上一本写作消息的文章里，我征集到了大约 40 条建议，虽然没能完全采纳，但我都一一考虑过这些很有价值的建议。对于这本新书，在内容、形式或是其他任何方面，你有什么意见和建议？欢迎发评论分享你的想法，谢谢。</p>
]]></content:encoded>
			<wfw:commentRss>https://greyli.com/writing-another-flask-book/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
	</channel>
</rss>
