获取CSV/PDF格式产品数据的RESTful API端点设计咨询
如何设计符合RESTful规范的产品数据导出端点?
好问题!咱们从RESTful的核心「资源导向」原则出发,来梳理最合理的设计方案,同时对比你初步设想的思路:
最优方案:利用HTTP Accept 请求头(最贴合RESTful规范)
REST的核心思想之一是同一资源可以有多种表现形式(Representation),导出的CSV/PDF格式JSON本质上就是产品资源的两种不同输出形态,完全可以复用现有的GET /products端点,通过HTTP标准的Accept请求头来区分需要的格式。
具体做法:
- 定义自定义的媒体类型来标识两种导出格式:
- 对于PDF格式的JSON结构,使用
Accept: application/vnd.yourcompany.products+pdf+json(这里的yourcompany换成你的业务标识,避免和标准媒体类型冲突) - 对于CSV格式的JSON结构,使用
Accept: application/vnd.yourcompany.products+csv+json
- 对于PDF格式的JSON结构,使用
请求示例
获取PDF格式的JSON数据:
GET /products HTTP/1.1 Host: your-api-domain.com Accept: application/vnd.yourcompany.products+pdf+json响应返回你需要的PDF专属结构:
{ "products_pdf": { "title": "Products", "sub_title": "as per May 20 2018", "products": [ { "name": "product A" }, { "name": "product B" } ] } }
获取CSV格式的JSON数据:
GET /products HTTP/1.1 Host: your-api-domain.com Accept: application/vnd.yourcompany.products+csv+json响应返回简洁的CSV专属结构:
{ "products_csv": [ { "name": "product A" }, { "name": "product B" } ] }
这种方案的优势:
- 完全符合REST的资源导向原则,不需要为输出格式新增独立的资源路径
- 扩展性极强,以后新增Excel等格式,只需要定义新的媒体类型,不用修改URL结构
- 利用HTTP标准头做内容协商,是REST架构推荐的标准做法
妥协方案:用查询参数指定格式(如果无法自定义Accept头)
如果调用导出服务的系统有技术限制,没办法设置自定义的Accept头,那可以退而求其次用查询参数来指定格式,端点设计为:
GET /products/export?format=pdfGET /products/export?format=csv
这里用/export作为产品资源的子操作,用查询参数format来指定输出形态,比把格式放到路径里更合理——因为路径参数通常用来标识唯一的资源实体,而格式只是输出选项,用查询参数更符合REST的语义。
关于你初步设想的端点的小问题
你之前想的GET /products/exports/{:file_format}或者/products/exports/csv这类设计,其实是把每种格式当成了独立的资源,但本质上它们都是产品资源的不同输出形式,这样设计会让URL结构冗余,以后新增格式就得不断加新的路径,不符合REST的简洁性和扩展性原则。
总结下来,优先推荐用Accept头的方案;如果有技术限制,再用查询参数的方式。
内容的提问来源于stack exchange,提问作者deerawan




