我正在帮助为现有数据库开发新的 API。
我正在使用 Python 2.7.3、Django 1.5 和 django-rest-framework 2.2.4 以及 PostgreSQL 9.1
我需要/想要良好的 API 文档,但我人手不足,而且我讨厌编写/维护文档(我的众多缺陷之一)。
我需要允许 API 的消费者添加新的“POS”(销售点)位置。 在Postgres数据库中,有一个从pos到pos_location_type的外键。 所以,这是一个简化的表结构。
pos_location_type(
id serial,
description text not null
);
pos(
id serial,
pos_name text not null,
pos_location_type_id int not null references pos_location_type(id)
);
因此,为了允许他们发布新的 pos,他们需要给我一个“pos_name”和一个有效的 pos_location_type。 所以,我整个周末都在阅读这些内容。 那里有很多争论。
我的 API 使用者如何知道 pos_location_type 是什么? 或者这里传递什么值?
看来我需要告诉他们在哪里可以获得有效的 pos_locations 列表。 比如:
GET /pos_location/
快速说明一下,pos_location_type 描述的示例可能是:(“学校”、“公园”、“办公室”)。
我真的很喜欢 Django REST Framework 的“可浏览性”,但是,它似乎并没有解决这类问题,实际上今天早些时候我在 IRC 上与 Tom Christie 进行了一次非常愉快的交谈,但他没有真的有一个关于在这里做什么的答案(或者也许我从来没有明确我的问题)。
我看过 Swagger,这是一个非常酷/有趣的项目,但是请在 演示中 看看他们的“宠物”资源。 请注意,它与我需要做的非常相似。 要添加新宠物,您需要传递一个类别,他们将其定义为 class Category(id: long, name: string)。 消费者如何知道要在这里传递什么? 什么是有效id? 或者名字?
在 Django Rest 框架中,我可以定义/覆盖 OPTION 调用中返回的内容。 我想我可以在这里想出我自己的小“系统”并返回一些信息,例如:
pos-location-url: '/pos_location/'
在通用形式中,它将是:{resource}-url: '/path/to/resource_list'
这对于文档方面来说是有用的,但我不确定这是否真的是一个很好的编程解决方案。 如果我更改资源位置怎么办?这意味着我的消费者需要以编程方式调用资源来找出所有关系。 也许不是坏事,但感觉有点奇怪。
那么,人们如何处理这种事情呢?
最后的注释:我知道我真的不想在这里出现“泄漏”抽象,并且让我的数据库通过 API 层达到峰值,但事实仍然是这个现有数据库和任何插入都存在foreign_key约束没有有效的 pos_location_type_id 会引发错误。
另外,我并不是想引发 URI 与 ID 的争论。 用户是否必须使用 pos_location_type_id int 值或 URI 对于 this 讨论并不重要。 无论哪种情况,他们都不知道要发送什么给我。
我过去曾处理过这类事情。我认为有两种方法可以解决这个问题,第一种方法你已经说过了,允许 API 用户的端点知道
pos_location_type
的类似 id 的值是什么。许多 API 这样做是因为从您的 API 进行开发的人必须阅读您的文档并知道从哪里获取 pos_location_type
值。最终用户不必担心这一点,因为他们将有一个界面,可能显示文本值的下拉列表。
另一方面,我的工作方式也不太像 RESTful。假设您在纽约有一个位置,并且 POST 可能类似于:
POST /pos/new_york/
您可以通过规范化文本来处理 /pos/(location_name)/ ,然后只需在数据库中搜索值或某些相似性,如果地点不存在,则只需创建一个新地点。如果用户可以添加新地点,如果不能,则用户必须知道存在哪些固定地点,这又是我们所处的第一种情况。
这样您就可以避免请求数据中出现
pos_location_type
,您可以通过编程将其映射到有效 ID。
您可以有一个端点“/dictionaries”,它以 json 形式返回所有主表数据,并以键作为表名。和值作为记录数组。
您还可以使用不同的子路径按用途对表进行分组,例如 “/dictionaries/games”仅返回使用外键创建游戏记录所需的几个主表数据。