2

I have a question regarding HTTP methods and what would be most proper in terms of conforming to REST principles.

I have two services, A and B. When new data is added, or old data is updated at Service A (e.g. POST/PUT) it triggers Service A to contact Service B to let it know that new data is available. Then Service B requests data from Service A via a GET endpoint and caches the response for later use.

What would be a good method of triggering this process to happen in Service B? The process that happens inside Service B goes as follows:

  • Receive trigger
  • Clear cache
  • Request data (GET Service A)
  • Cache response

So this process clears the current cached data and then stores new information to the same cache.

I was thinking a HEAD request would be good, as we are not sending any data from Service A, nor expecting any response - just letting Service A know, that it should do something.

I read from somewhere, that a GET/HEAD request should not alter the state of a service, so perhaps this wouldn't exactly comply with REST principles. In this case, would PUT method be more appropriate, because we are updating/renewing the cache? Even though the PUT trigger would have an empty request body?

Service communication overview

One suggestion was to use a PUT endpoint at Service B and to just deliver the new data, and have no pull mechanism, but then the PUT endpoint needs some authentication. Using a trigger GET/HEAD method would just let Service B know that it needs to fetch new data. Service A knows the URL of Service B beforehand, and would request data from there, regardless of who activated the trigger, so Service B doesn't use the requestor's URL.

EDIT: For the duplicate suggestion, I suppose the meta-question of this problem is: "Is there a RESTful method to trigger a state change in a web server, without delivering data?" Yes: I wonder what that would be. No: It's not a RESTful web service.

Teemu
  • 131
  • 1
  • 4
  • So the request to service B is: unsafe and no cacheable. It doesn't have request body and there's not going to be response body either. Service B can send back HTTP 200/204 OK to that request. So, the only question is: Is it idempotent? If it's, perhaps [TRACE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/TRACE) could do the job. [Http Methods catalog](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) – Laiv Mar 14 '19 at 13:39
  • 1
    Regarding Bart's comment. Only this [asnwer](https://softwareengineering.stackexchange.com/a/261647/222996) seems convincing – Laiv Mar 14 '19 at 14:04
  • There is a change in semantics once Service A is notifying Service B. A becomes a client to B in that piece of the transactional flow. If you inserted a event message bus / queue between the services to proxy their communications, it becomes more clear that A is a client in that case. Closing as duplicate as I don't see a new question outside of what's already covered. –  Mar 16 '19 at 14:53

4 Answers4

3

What would be a good method of triggering this process to happen in Service B?

First point: if A and B are both under your control, it may not matter very much which method you use, because whether or not your semantics are aligned with the HTTP protocol, both ends are using the same semantics.

But supposing you had to do it "right", because reasons....

RFC 7231 briefly outlines common properties of HTTP methods.

Safe is an important one, because it implies that the request can be sent speculatively. For example, a generic client can proactively submit GET requests for links that it sees. Spiders can crawl them. Caches can pre-fetch.

If that's not satisfactory in your domain application protocol, (perhaps because the server is going to react to the request by doing something expensive), then GET and HEAD are not appropriate choices.

A thing to keep in mind - if you are trying to use GET/HEAD to propagate a signal, you had best be sure that the metadata in the response does not encourage caching - a cache might short circuit the round trip to your subscriber and return a previously cached response.

Idempotent is important on unreliable networks - if two copies of the request are equivalent to a single copy, then idempotent semantics allow generic components to autonomously resend unacknowledged requests. Effectively, you are advertising that at least once delivery strategies can be used.

PUT is unsafe, but idempotent. If you cannot comfortably handle multiple copies of the "same" message, then cross PUT off of the list.

POST is neither safe nor idempotent -- the semantics of POST are so broad that they encompass every other use case. This produces the opposite problem: because the semantics are so broad, generic components cannot contribute anything useful to improve the experience.

VoiceOfUnreason
  • 32,131
  • 2
  • 42
  • 79
0

This is pretty interesting, and you're not far off with HEAD. I checked out this answer on software engineering while thinking about this question, and their suggestion is pretty applicable here; You're going to need to make a choice and explain it, but GET is probably the best option.

The reason behind this is that you're describing a Stateful action, either the cache has current data in it or not, making it a little awkward to fit into a RESTful api. No worries though; just make sure to document your choice and explain it so whomever comes next can understand why you did what you did.

Adam Wells
  • 908
  • 4
  • 15
0

I suggest that you should use POST method and create an exceptional rule for this API on service 2 so that you can bypass the authentication when calling this endpoint.

Why I suggest using POST:

  • the state of the service 2 may be different after multiple calls of this API (therefore I don't use PUT)
  • the state of the service 2 may be changed after each call of this API and the request should not be cached (therefore I don't use GET/HEAD)

Honestly, I will use an event/message bus in this scenario to avoid API calls that only trigger other actions like this.

Hieu Le
  • 663
  • 4
  • 10
0

There are a couple of good answers already, here's an additional idea that might make sense: treat the cache as a resource of service B that has an attribute "valid". Signal the need for re-caching by setting this attribute to False using a PUT request to /cache/:id/valid. The cache resource should only be accessible to service A, and it probably does not need a GET handler to provide read access except when you think this could be useful for debugging.

Hans-Martin Mosner
  • 14,638
  • 1
  • 27
  • 35