Как использовать ETag / If-Match с несколькими элементами

Рекомендуемый способ обработки оптимистической блокировки в интерфейсе RESTful заключается в возврате ETag из ПОЛУЧИТЬ, и поставляя If-Match на PUT, то есть:

GET /items/1  --> gives client an ETag for a single item
PUT /items/1  <-- client gives it back as If-Match for checking

Как использовать эту схему с несколькими элементами, например, если я хочу получить пакетные GET для получения нескольких элементов из одного URI:

GET /items    --> How do I return multiple ETags for multiple items here? 

В качестве альтернативы, если ETags/If-Match не справляется с этой ситуацией, каков рекомендуемый подход? Или я должен просто свернуть свой?

2 ответа

Решение

tl; dr: все в порядке, чтобы назначить etags для ресурса, который содержит "коллекцию", но это приложение должно управлять идентификацией / изменением элементов в этой коллекции при определении действительного etag.

Ресурс в архитектурном стиле REST не подразумевает, что это отдельный элемент или коллекция. Он просто представляет состояние приложения в данной точке рабочего процесса. Ресурс будет содержать описательные данные и, надеюсь, ссылки на возможные последующие шаги в этой точке рабочего процесса. Рабочий процесс может быть таким же простым, как получение статуса заказа, или сложным, как оформление заказа на сайте электронной коммерции с возможностью отмены заказа.

Этаг - это механизм определения того, является ли конкретное состояние (ресурс) актуальным или нет. Присвоение etag ресурсу, который возвращает коллекцию данных, означает, что ваше приложение идентифицирует это состояние элементов коллекции в этой точке, и если что-либо в этих элементах изменится, предыдущее значение etag больше не будет действительным. Ваше приложение должно решить, когда элементы коллекции изменятся и как идентифицировать отдельные элементы. Другими словами, etags применяются к ресурсам, но не к отдельным компонентам данного ресурса.

В случае агрегатов версия агрегата должна быть версией последней обновленной части. С источником событий это очень просто, потому что вы можете использовать идентификатор события для управления версиями.

Что касается вашей коллекции элементов, etag ресурса коллекции должен быть etag последнего обновленного ресурса элемента. Для каждого элемента вы должны описать etag в их гиперссылках или, если все гиперссылки имеют одинаковую версию в одном и том же ресурсе, вы можете описать версию в содержащем их ресурсе.

Так, например, если элемент 4 был обновлен последним, то GET /itemsдолжно вернуть что-то вроде:

      {
    "type": "/doc/ItemSet",
    "version": "3q2teg3234",
    "label": "The Collection of Expensive Items",
    "size": 2,
    "items": [
        {
            "type": "/doc/Item",
            "version": "f233425wfsw",
            "id": "1",
            "label": "Bugatti Veyron",
            "links": [
                {
                    "label": "Read item",
                    "type": "/doc/Item/methods/read"
                },
                {
                    "label": "Update item",
                    "type": "/doc/Item/methods/update"
                }
            ]
        },
        {
            "type": "/doc/Item",
            "version": "3q2teg3234",
            "label": "Porsche 911",
            "id": "4",
            "links": [
                {
                    "label": "Read item",
                    "type": "/doc/Item/methods/read"
                },
                {
                    "label": "Update item",
                    "type": "/doc/Item/methods/update"
                }
            ]
        },
    ],
    "links": [
        {
            "label": "List items",
            "type": "/doc/ItemSet/methods/list"
        }
    ]
}

офк. вы можете отправить описания гиперссылок, например /doc/Item/methods/updateв том же документе тоже, но лучше что-то многоразовое, например:

      {
    "type": "/doc/HyperLinkTemplate",
    "method": "PUT",
    "uri": "/api/items/{id}",
    "headers": {
        "ETag": "{version}"
    },
    "body": {
        "label": "{label}"
    },
    "parameters": {
        "version": {
            "type": "/doc/ResourceVersion",
            "value": {
                "type": "doc/Query",
                "query": "{context/containingResource/version}"
            },
            "writeable": false
        },
        "id": {
            "type": "/doc/Item/id",
            "value": {
                "type": "doc/Query",
                "query": "{context/containingResource/id}"
            },
            "writeable": false
        },
        "label": {
            "type": "/doc/Item/label",
            "value": {
                "type": "doc/Query",
                "query": "{context/containingResource/label}"
            },
            "writeable": true
        }
    }
}

Это зависит от вашего клиента, как он использует гиперссылку. Из него даже можно создать HTML-форму, хотя REST в основном предназначен для связи M2M.

Другие вопросы по тегам