Return=minimal - 204 no-content is confusing

Although the current REST behaviour, providing a lto of 204 codes, on successful transactions, is correct, it is pretty confusing for developers, and there seems to be no agreement on minimal responses that might trigger 200 or 201 responses that would be expected by a lot of devs.

Could we agree that return=minimal should (at minimal!!) return the contents of the ETag

e.g.
/composition - the uid
/ ehr - the ehr_id/value

etc.

IMO this will make the API much easier to navigate and use.

1 Like

Dear Ian,

You are quite right there. We also struggled a little bit when we started testing EHRBase. Minimal should not be nothing.

regards

1 Like

While I understand the general problem here, I think it is actually correct how it is.

Returning “the contents of the ETags” is problematic, because just the content is no valid document. For instance, it is neither JSON nor XML. Of course it could be formatted that way, but then we have a full (yet small) valid body and therefore no 204 situation anymore.
On top of that, I just don’t see the necessity here, as the ETag header already contains that information. As a developer, I can easily access the header data. And why transfer the same piece of data twice?

But I’m not very experienced in web standard implementations and don’t know how other big tools or APIs are handling that. So if the best practice is to navigate around 204s I would like to learn more about that.

Some references, just for the sake of completeness:

10.2.5 204 No Content

The server has fulfilled the request but does not need to return an entity-body […]

See: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

4.2. The “return=representation” and “return=minimal” Preferences

[…] The “return=minimal” preference, on the other hand, indicates that the client wishes the server to return only a minimal response to a successful request. Typically, such responses would utilize the 204 (No Content) status […]

See: https://tools.ietf.org/html/rfc7240#page-8

1 Like

Hi Jake,

My understanding is that @sebastian.iancu and the other designers of the REST API tried very hard to do the design ‘correctly’ - exactly as you suggest.

The problem I see is that this is not actually how most of the real-world rest services actually operate. In that sense I am a good example of a naive web-app developer. I had never seen a 204 before (for a valid response) and the Rest client library I was using (fairly mainstream) made it very hard to extract a header tag in the response, compared to parsing the response body - trivial.

We might be in danger of doing the ‘right thing’ in IETF terms but confusing the rest of the world who have never head or seen 204 being used for a successful transaction.

Thanks for the references. My suggestion is that we construct some simple very minimal ‘default’ response bodies - essentially the ETags. If people want to go super-minimalistic they can set return=minimal and get a 204.

Yes @jake.smolka you are very right about it, this is the way it should be if you follow REST standards - it might not look very friendly (but not confusing), …but it is anyway consistent.
ETag is not a valid option to rely for that id, I would rather suggest the Location header.
We have a ticket now, SPECITS-50 and we’ll consider of making this a bit more user friendly, for instance by adding extra openEHR-headers for uid, or using another (own) return type that allows references or a sort of “operationOutcome” - we need to investigate which one is better.

I would definitely push for something coming back in the body.

It is just much,much easier to access/process that from typical REST libraries. Handling response Headers is often very obscure and badly documented, in my (limited but probably typical) experience. The exact format is not so important.

It is very common to need to do some sort of operation on a key identifier being produced e.g the compositionID or ehrId, templateId. Queries work fine as they are - 204 for an empty result is fine

Should I think in this direction: https://www.hl7.org/fhir/http.html#ops, returning a sort of operation outcome, or just only the uid-reference of the resource created or updated?

ACtually that is quite confusing - the details for the different operations suggests sending 200s and 204s but does not specify any default body content. Implies to me (may be quite wrong) that the correct response to e.g a successful POST is a 201, even if the body response is empty’ unless return=minimal is set when it should be a 204.

THe Operation-Outcome seems overly complicated. For the few resource where this is an issue, I would favour just a very simple uid-reference being returned. It is very convenient to have it there and it prevents the 204 issue unless someone explicitly sets ‘minimal’. THe only exception might be templates where having uid as well as templateId might be helpful

Once you get used to it, it becomes clear; it might be confusing in the beginning if you are not doing this on the daily bases. Not all programmers are web-programmers, and even if they are, then not all of them are programming/design/using restful services. It is apparently simple, and yet it isn’t. It requires experience to be gained. It is perhaps like designing good archetypes, implementing the right design pattern: everybody using AD can create an archetype, but that’s not always the best archetype, and a lot of AD features might remain unused and unknown to those user.

Back to our specs, I think we should always try to make things clear and easier, although we should also comply with standards and best practices, even when they might be apparently confusing.

To further explain on the problem/principle you started above:

  • RESTful services are dealing with Resources, in our case any of COMPOSITION, EHR, FOLDER, etc.
  • when you create (POST), you get back the persisted resource (representation) with code 201 and location, or an ok-but-no-content 204 and the location, in case the preference is to keep http low (return-minimal, just headers)
  • when you update (PUT) or create at your location (create using PUT), you get back 200 if update was ok or 201 if you created something new, both with resource in the body (i.e. representation) or you get 204 with no-body and only header, if you prefer minimal response (i.e. headers only)
  • in standard interaction with restful services you cannot expect that the returned resource has different (semantic) type than the resource in the request - i.e. you cannot usually save composition and get back an id (as body)
  • http negotiation is important: server should be able to deal with many client preferences, and clients should know what/how to ask the server; so headers, status codes
  • adding extra returned headers is allowed and should be easy to for clients to process
  • changing return body type is acceptable as long as is requested (with prefer header), and there we could add only the uid value - not very restful interaction, but at least is consistent and could be nicely documented.

Hope this clears some confusions - I am myself not a REST expert, just following places like:

@ian.mcnicoll They would be the perfect resource to do a field study on. Can you please show us the real-world REST services that apply REST different than the openEHR REST API :slight_smile:
Also, can you share what REST client library you worked with? From the client perspective, I’m working with tools like Postman and Insomnia on a daily basis and both can access response headers easily. So I never had any problem with them.

Currently the spec says:

In case no Prefer header is present in request, the default response policy is return=minimal.

Maybe we could switch the defaults here. Would that be less confusing, if a request without any specific Prefer header would just respond with the full response object (incl. its object or version ID)?
The negative implications I can think of right now would only impact performance or bandwidth. Would there be more to consider @sebastian.iancu?

We could switch the default behavior to representation, if that’s what raised and acceptable by SEC group (need to discuss if there would be side effects in existing implementations).

1 Like

I would say that may bring the default closer to what is more convenient for the developer.

I’m currently implementing a bunch of examples to connect a clinical application’s backend to our current REST implementation (which is pretty out of date tbh) and when I put myself into the position of the developer who’ll use my code as a starting point; I can see that the most convenient thing would be to have whatever composition he/she POST’ed to the endpoint returned as the payload of the response.

That’s what’d feel more natural to me, because in the happy path/scenario, I’ll push a composition and get back one with a uid value in the composition payload, which I can then use or throw away.

It’s not only about the uid value (which’ll be in the location header as well) I have a habit of trying to switch to persisted representation of clinical data as early as possible in the code. So if I need to push something to CDR and then use it for any purpose, I’d rather use the persisted version than the one I sent over the wire, because if anything went wrong (I forgot to map an optional data item to the composition dto etc), using the persisted version will break my tests and I’ll know about it.

Yes, I can still make another req and get the persisted version but having it around in the body of 201 is more convenient. I appreciate this is highly subjective, and I may be violating some REST principal but from a productivity point of view, I find this to be a pragmatic approach.

This is highly subjective, so I won’t get into a discussion to defend it, but I wanted to make the point that there is at least one member of SEC who thinks it’d help to have the default returning the full representation :slight_smile:

yes, it is subjective, but I can relate to this also.

I’d still prefer a representation that had something simpler than the full resource as default - are we going to do the same for the POST /template and return the full .opt

However … at least defaulting to return=representation will prevent ‘accidental’ 204 messages.

Appreciate that what I am suggesting is ‘REST-heresy’ but all of these little tings just put barriers in the way for folks who do not have time to understand the ‘correct’ approach.

Examples of the fiddly things that come into play when you use response headers with typical client libraries.

None of this means that Response headers are wrong but they are fiddly to process and not well supported ‘out-of-the box’ in typical REST library documentation.

I would not be too bothered if opt POST endpoint behaved the same, but that’s a much less frequently invoked call compared to a POST to …/composition endpoints, so the benefit I see and describe above does not apply.

for compositions, I don’t think we can ever agree on a brief subset of a composition to be returned in the body, that’s just too subjective to be a useful default. If you can identify a useful subset which you can then request with representation=ians_super_duper_composition_subset header, then it may be a nice convenience, but unlikely to be hit the 80/20 mark as a default behaviour.

For /composition … the new/updated compositionID, for /ehr the new/updated ehr_id/value, for /template the new/updated templateId.

Job done and the body is shorter than the original header “representation=ians_super_duper_composition_subset” :space_invader:

you’re just asking for a content level representation of what is in the headers. In this case, you shall not have my sympathy Dr. McNicoll :stuck_out_tongue: Just parse your headers like everybody else. :smiling_imp:

I merely ask on behalf of the ‘Restfully-challenged’, the ‘left behinds’, the ‘Deplorables’… ah sorry wrong thread… :nauseated_face: