Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
Changelog
=========

[0.7.6] - Unreleased
--------------------

Added
^^^^^
- Support for ETags: ``replace``, ``modify`` and ``delete`` automatically send
an ``If-Match`` header when the server advertises ETag support and the resource
has a ``meta.version``. :issue:`47`
- ``query`` sends an ``If-None-Match`` header when passed a resource instance
with ``meta.version`` and the server supports ETags. On ``304 Not Modified``
the original instance is returned. :issue:`47`

Breaking changes
^^^^^^^^^^^^^^^^
- ``query`` now takes a resource type, a resource instance, or ``None`` instead
of a resource type and id. :issue:`13`
- ``delete`` now takes a resource instance instead of a resource type and id.
:issue:`13`
- ``modify`` now takes a resource instance and a patch operation instead of a
resource type, id and patch operation. :issue:`13`

[0.7.5] - 2026-04-02
--------------------

Expand Down
46 changes: 44 additions & 2 deletions doc/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ The :meth:`~scim2_client.BaseSyncSCIMClient.modify` method allows you to perform
patch_op = PatchOp[User](operations=[operation])

# Apply the patch
response = scim.modify(User, user_id, patch_op)
user = scim.query(User(id=user_id))
response = scim.modify(user, patch_op)
if response: # Server returned 200 with updated resource
print(f"User updated: {response.display_name}")
else: # Server returned 204 (no content)
Expand Down Expand Up @@ -155,7 +156,7 @@ You can include multiple operations in a single PATCH request:
)
]
patch_op = PatchOp[User](operations=operations)
response = scim.modify(User, user_id, patch_op)
response = scim.modify(user, patch_op)

Patch Operation Types
~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -201,6 +202,47 @@ To achieve this, all the methods provide the following parameters, all are :data
which value will excluded from the request payload, and which values are
expected in the response payload.

Resource versioning (ETags)
==========================

SCIM supports resource versioning through HTTP ETags
(:rfc:`RFC 7644 §3.14 <7644#section-3.14>`).
When the server advertises ETag support in its
:class:`~scim2_models.ServiceProviderConfig`, scim2-client automatically sends
an ``If-Match`` header on write operations
(:meth:`~scim2_client.BaseSyncSCIMClient.replace`,
:meth:`~scim2_client.BaseSyncSCIMClient.modify`,
:meth:`~scim2_client.BaseSyncSCIMClient.delete`)
using the :attr:`meta.version <scim2_models.Meta.version>` value from the resource.

This enables optimistic concurrency control: the server will reject the request
with ``412 Precondition Failed`` if the resource has been modified since it was
last read.

For read operations, :meth:`~scim2_client.BaseSyncSCIMClient.query` sends an
``If-None-Match`` header when passed a resource instance with
:attr:`meta.version <scim2_models.Meta.version>`. If the server responds with
``304 Not Modified``, the original instance is returned without parsing.

.. code-block:: python

# Read a resource — meta.version is populated by the server
user = scim.query(User(id=user_id))

# Re-read — If-None-Match is sent; returns the same object on 304
user = scim.query(user)

# Modify it — If-Match is sent automatically
user.display_name = "Updated Name"
updated_user = scim.replace(user)

# Delete it — If-Match is sent automatically
scim.delete(user)

No additional configuration is needed. If the server does not advertise ETag
support, or if the resource has no :attr:`meta.version <scim2_models.Meta.version>`, no
conditional header is sent.

Engines
=======

Expand Down
Loading