添加指向实现HATEOAS的python-eve API资源的链接

时间:2014-10-21 13:46:03

标签: python hateoas eve

我正在使用python-eve构建API。

我的设计很简单,它有两个资源,用户和设备:

  • /用户[/ ID]
  • / users / ID / devices [/ ID]

代码是( settings.py ):

users_schema = {
  'nickName': {
    'type': 'string',
    'required': True,
  },
  'email': {
    'type': 'string',
    'required': True,
    'unique': True
  }
}

devices_schema = {
  'name': {
    'type': 'string',
    'required': True,
  },
  'user_id': {
    'type': 'objectid',
     'data_relation': {
        'resource': 'users',
        'embeddable': True
    },
  }
 }

users = {
  'item_title': 'user',
  'url': 'users',
  'schema': users_schema,
}

user_devices = {
  'resource_title': 'devices',
  'url': 'users/<regex("[a-f0-9]{24}"):user_id>/devices',
  'schema': devices_schema,
  'datasource': {
    'source': 'devices',
  }
}

DOMAIN = {
 'users': users,
 'user_devices': user_devices 
}

如果我创建用户,则用户资源看起来像( / users / 54465ae80640fd0f60f6aa09 ):

{
"_updated": "Tue, 21 Oct 2014 13:08:56 GMT",
"_etag": "d6ff9457f5b196a8c245a7dc91e7fca0d28c5268",
"_links": {
    "self": {
        "href": "/users/54465ae80640fd0f60f6aa09",
        "title": "user"
    },
    "parent": {
        "href": "",
        "title": "home"
    },
    "collection": {
        "href": "/users",
        "title": "users"
    }
},
"_created": "Tue, 21 Oct 2014 13:08:56 GMT",
"_id": "54465ae80640fd0f60f6aa09",
"nickName": "superuser",
"email": "super@user.com"
}

默认情况下启用HATEOAS。 在之前的资源中,我期望链接到用户设备, / users / 54465ae80640fd0f60f6aa09 / devices ,因为此端点存在,在代码(user_devices)中定义,并且工作正常。

我可以让pyhon-eve了解用户用户设备之间的关系,将此设备链接添加到用户资源?否则,用户54465ae80640fd0f60f6aa09将不知道如何获取设备。

我期待的是:

{
"_updated": "Tue, 21 Oct 2014 13:08:56 GMT",
"_etag": "d6ff9457f5b196a8c245a7dc91e7fca0d28c5268",
"_links": {
    "self": {
        "href": "/users/54465ae80640fd0f60f6aa09",
        "title": "user"
    },
    "devices": {
        "href": "/users/54465ae80640fd0f60f6aa09/devices",
        "title": "devices"
    },
    "parent": {
        "href": "",
        "title": "home"
    },
    "collection": {
        "href": "/users",
        "title": "users"
    }
},
"_created": "Tue, 21 Oct 2014 13:08:56 GMT",
"_id": "54465ae80640fd0f60f6aa09",
"nickName": "superuser",
"email": "super@user.com"
}

如何获取设备的“显而易见”。

非常感谢。

2 个答案:

答案 0 :(得分:1)

您必须在user =&gt;之间添加链接设备太

users_schema = {
      'nickName': {
        'type': 'string',
        'required': True,
      },
    'data_relation': {
        'resource': 'user_devices',  # link to device on a field _id
        'field': '_id',
        'embeddable': True
    },
      'email': {
        'type': 'string',
        'required': True,
        'unique': True
      }
    }

答案 1 :(得分:0)

我创建了一个自定义钩子,以将一个项目与其他集合链接起来。

将下一个代码添加到您的应用中,然后定义您的商品和相关集合之间的data_relation。

例如,我有通过parent_node链接的菜单,因此我在架构上有两个关系:

  • 其中哪个parent_menu是当前项目->子项
  • parent_menu->儿童

所以我有下一个模式(孩子的第一个关系第二个给父母):

"menu": {
  "type": "dict",
  "schema": {
    "_id": {
      "type": "objectid",
      "data_relation": {
        "resource": "menu",
        "field": "parent_menu",
        "embeddable": False,
      }
    },
    "id": { "type": "string" } ,
    "label": { "type": "string" },
    "url": { "type": "string" },
    "parent_menu": {
      "type": "objectid",
      "data_relation": {
        "resource": "menu",
        "field": "_id",
        "embeddable": True,
      },
    },
  },
},

这是呈现根菜单的方式(不是父菜单,只有具有link_rel“ menu”的子菜单:

{
  "_id":"5c6ab8a5467a938b027aae64",
  "id":"root",
  "label":"Home",
  "url":"/",
  "_links":{
    ...
    "self":{
      "title":"Menu",
      "href":"menu/5c6ab8a5467a938b027aae64"
    },
    ...
    "menu":{
      "title":"menu",
      "href":"menu?where={\"parent_menu\":\"5c6ab8a5467a938b027aae64\"}"
    }
  }
}

这是孩子的样子(父母和孩子链接):

{
  "_id":"5c6ab8a5467a938b027aae65",
  "id":"submenu1",
  "label":"Submenu1",
  "url":"/#submenu1",
  "parent_menu":"5c6ab8a5467a938b027aae64",
  "_links":{
    ...
    "self":{
      "title":"Menu",
      "href":"menu/5c6ab8a5467a938b027aae65"
    },
    ...
    "menu":{
      "title":"menu",
      "href":"menu?where={\"parent_menu\":\"5c6ab8a5467a938b027aae65\"}"
    },
    "parent_menu":{
      "title":"menu",
      "href":"menu/5c6ab8a5467a938b027aae64"
    }
  }
}

该应用的代码:

def createLink(ref_collection, ref_field, ref_value):

    print(f"createLink({ref_collection}, {ref_field}, {ref_value})")
    ref_value = f"{ref_value}"
    linkSufix = "/" + ref_value if ref_field == "_id" else "?where={\"" + ref_field + "\":\"" + ref_value + "\"}"

    linkRel = {
        "title": ref_collection,
        "href": ref_collection + linkSufix,
    }
    print(f"createLink result: \n{linkRel}")

    return linkRel

def add_links(resource_name, resource, schema):

    linked_item_keys = list(key for key in schema if "data_relation" in schema[key] and key in resource)
    print(f"linked_item_keys: {linked_item_keys}")

    for key in linked_item_keys:

        print(f"link needed for: {resource_name}.{key}")
        itemSchema = schema[key]
        item = resource[key]

        data_relation = itemSchema["data_relation"]
        ref_collection = data_relation["resource"]
        ref_field = data_relation["field"]

        link = createLink(ref_collection, ref_field, item)

        links = resource["_links"] if "_links" in resource else []
        link_rel = ref_collection if resource_name == ref_collection  and key == "_id" else key
        links[link_rel] = link
        resource["_links"] = links

def add_links_to_item(resource_name, response):
    print(f"------------------------------------")
    print(f"(on_fetched_item) {resource_name} ")
    print(f"response: \n{response}")

    schema = config.DOMAIN[resource_name]["schema"]
    print(f"""schema: \n{schema}""")
    add_links(resource_name, response, schema)

app = Eve()
app.on_fetched_item += add_links_to_item

希望有帮助!