0

We have many clients which, upon start up, request a specific resource on the server using an HTTP API (not RESTful). This resource is - currently, identical for all clients.

Naturally, since the client is requesting data from the server via HTTP, a GET is used.

Incidentally, we wish to log the access of this resource as it is vital to the startup phase of each client and represents potentially valuable support information.

The HTTP spec, however, states in no uncertain terms that a GET should not have any side effects (section 9.1.1). I can think of several possible solutions to this issue:

  1. Have the clients perform a POST, as it is not an idempotent action.

  2. Do not heed the spec (after all, it is a should not) and update the last access time for the given client when the GET is performed.

  3. Create post-method hooks which update the last access time for the given client.


1 is definitely not an option in our case, as our clients are not easily modified and even then do not have compulsory updates.

2 is likely the most straightforward option which guarantees that the business requirements are met.

3 is a possibility, yet necessitates (as far as I can see) an asynchronous update which then may fail as it is no longer part of the original request. Additionally, it necessitates the strong coupling of technical code with business logic, which is something we try to avoid.

As far as I can see, option 2 is the only course of action we could take as it fulfills our requirements while not completely stomping on the spec or ruining our code.

Are there other ways which would potentially be better? Is there perhaps another common way of logging access times to secured resources similar to audit logs via HTTP?

2
  • 2
    I wouldn't consider setting the last accessed timestamp a side effect but rather an aspect of auditing. Option two seems fine to me. – Dan Wilson Sep 19 '19 at 16:03
  • I see - you do have a point there. We also practice CQRS, and the GET naturally maps to a query. Could you elaborate how auditing may be combined with this approach? Should it perhaps be decoupled from the business logic, in this case? – user991710 Sep 19 '19 at 16:10
1

While not explicitly stated, when the spec is talking about about idempotence and side effects, it must be understood to be talking about the effects on the domain covered by the operation itself. This domain does not include metadata, since metadata is never part of the domain.

Indeed, if non-domain data was included, then essentially no HTTP GET (or any other) operation could be considered to idempotent and free of side effects, since HTTP requests are typically logged by the server itself! All requests therefore result in changes to the log, even if the request was required by the spec to be idempotent.

I would say that there are two ways to approach this - in the design of the code, or the design of the model. The approaches can be combined.

The model based solution is straightforward - don't store metadata on your entities. Store it elsewhere, such that the get operation remains idempotent in the context of the domain being queried. A log file perhaps. If your resource is a table in a database, then put the metadata in a different table, and join to it when you want to read it back out. (This is more sound relationally anyway, since metadata such as "last modified", "last accessed" and so on are not inherent properties of the entity in question and therefore do not belong as part of its definition).

The code based solution is to factor the code such that the get method itself only does the idempotent get, and the logging or auditing is done "elsewhere". The web server http log is of course an example of this approach. For this to be a valid design, the get handler can't itself call the logger, since that would put the logging within the scope of the get. The logger must be at a higher level.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.