spring-projects / spring-projects/spring-data-rest

Auto-populated Last-Modified header does not consider projections [DATAREST-613]

Open
#986 1 comment 0 reactions 1 assignee View on GitHub

@odrotbohm is already working on this.

Since Dec 31, 2020.

type: bug
Dominant language
Java
Stars
958
Forks
568
PR merge metrics
No merged PRs in 30d

Description

Chris Beams opened DATAREST-613 and commented

DATAREST-471 introduced support for auto-populating the Last-Modified header based on @LastModifiedDate auditing metadata. This works well for simple GET requests, but breaks down when projections are in the mix.

For example, consider an Assembly entity with a collection of Part entities, each being exposed by their own respective SD REST repositories, e.g.:

$ http localhost:8080/api/assemblies/1
{
    "_links": {
        "parts": {
            "href": "http://localhost:8080/api/assemblies/1/parts"
        },
        "self": {
            "href": "http://localhost:8080/api/assemblies/1"
        }
    },
    "assemblyAttr1": "val1"
    "assemblyAttr2": "val2"
}
$ http localhost:8080/api/assemblies/1/parts
{
    "_embedded": {
        "parts": [
            {
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/api/parts/1"
                    }
                },
                "partAttr1": "val1"
                "partAttr2": "val2"
            },
            ...
        ]
    },
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/assemblies/1/parts"
        }
    }
}

Both Assembly and Part are annotated with @LastModifiedDate, meaning that GET requests for individual Assembly or Part resources will respond with a Last-Modified header containing the date that the underlying requested entity was last modified.

Note, however, that a GET request for any collection of assemblies or parts does not respond with a Last-Modified header. That is, collection requests are never cached. This is not optimal from a caching perspective, but at least the client is guaranteed to get the freshest informaton.

But now consider the case of a GET request for an assembly with a projection that includes its parts, e.g.:

$ http localhost:8080/api/assemblies/1?projection=withParts

It's here that we run into trouble. The Last-Modified header will be returned in the response for this request, and it will contain the value of the @LastModifiedDate for the Assembly. If a Part has been added, deleted or updated in the meantime, the client will never know (without a hard-refresh or otherwise clearing or disabling the browser cache).

It seems to me, then, that auto-population of the Last-Modified header should either:

  1. carefully take projections into account, ensuring that the Last-Modified header reflects the most recently modified entity included in that projection, or
  2. punt, and avoid populating the Last-Modified header altogether if one or more projections have been specified in the query string. Basically, treat requests for projections like requests for collections are already treated.

Barring a quick implementation of either of the above, a stopgap measure would be to provide a way to disable auto-population of the Last-Modified header. Based on my reading of the implementation of this feature, I couldn't find a way to do it. I'm looking at stripping the header out with a Filter at this point


Affects: 2.4 M1 (Gosling)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.