【问题标题】:Adding links to a python-eve API resource implementing HATEOAS添加指向实现 HATEOAS 的 python-eve API 资源的链接
【发布时间】:2014-10-21 13:46:02
【问题描述】:

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

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

  • /users[/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 了解 useruser-devices 之间的关系,以便将此设备链接添加到用户资源?否则,用户 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"
}

在哪里“显而易见”如何获取设备。

非常感谢。

【问题讨论】:

    标签: python hateoas eve


    【解决方案1】:

    您也必须在用户 => 设备之间添加链接

    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
          }
        }
    

    【讨论】:

    • 嗨!谢谢!我试过了,但我仍然与“user”_links 中的“user_devices”没有任何关系。你能提供完整的代码吗?再次感谢!
    • data_relation 它提供的唯一想法是渲染完整对象,并在查询末尾添加?embedded={"user_devices._id":1}。预期的 HATEOAS 行为是创建一个新的 _link 部分,我认为 Eve 开箱即用并没有涵盖该部分
    【解决方案2】:

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

    将下一个代码添加到您的应用中,然后在您的项目和相关集合之间定义 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
    

    希望对你有帮助!!

    【讨论】:

      猜你喜欢
      • 2019-01-03
      • 2014-10-25
      • 2015-11-13
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2014-06-01
      • 2018-02-26
      • 1970-01-01
      相关资源
      最近更新 更多