PUT/POST validation: warnings/errors

114 views
Skip to first unread message

Jack Whelpton

unread,
Jan 28, 2015, 8:56:21 AM1/28/15
to api-...@googlegroups.com

Hi all,

 

Does anybody have any advice on how to include metadata in the response to a PUT or POST request that details problems that occurred during a save operation, but did not prevent creation of a resource? An example might clarify the problem. Suppose I have a widget resource:

 

{

  "id": "AAA",

  "name": "Widget A",

  "model-number": "A123"

}

 

Name is a required field, and model number must contain only alphanumeric characters. Business rules prohibit the saving of an invalid object. Handling resource creation via a POST to /widgets is straightforward; the response is either 201 Created, with a body that includes the full representation and identical Location and Content-Location headers:

 

HTTP/1.1 201 Created

Location: /widget/AAA

Content-Location: /widget/AAA

 

{

  "id": "AAA",

  "name": "Widget A",

  "model-number": "A123"

}

 

or 403 Forbidden with an HTTP problem details object, something like:

 

HTTP/1.1 403 Forbidden

Content-Type: application/json

{

  "type": "http://problems.example.com/invalid-model-number",

  "title": "Model number must contain only alphanumeric characters.",

  "detail": "You attempted to create a widgets with a model number of '#A123', but this model number is invalid."

}

 

Now the business rules are changed slightly, so that if an attempt is made to save a widget with an invalid model number, the widget will be created without a model number and the client notified of the fact. We could extend the representation to include a "warnings" node, and populate it only on PUT/POST responses:

 

HTTP/1.1 201 Created

Location: /widget/AAA

Content-Location: /widget/AAA

 

{

  "id": "AAA",

  "name": "Widget A",

  "warnings": [

    {

      "type": "http://problems.example.com/invalid-model-number",

      "title": "Model number must contain only alphanumeric characters.",

      "detail": "You attempted to create a widgets with a model number of '#A123', but such a model number is invalid."

    }

  ]

}

 

However, I'm not sure adding this property is a particularly good idea; it could collide with a genuine property of widgets, and the Content-Location header is now not strictly accurate, as the included representation is not available at that URI (warnings are not persisted). We could separate the resource representation from any warnings:

 

HTTP/1.1 201 Created

Location: /widget/AAA

Content-Location: /widget/AAA

 

{

  "result": {

    "id": "AAA",

    "name": "Widget A"

  },

  "warnings": [

    {

      "type": "http://problems.example.com/invalid-model-number",

      "title": "Model number must contain only alphanumeric characters.",

      "detail": "You attempted to create a widgets with a model number of '#A123', but such a model number is invalid."

    }

  ]

}

 

Again, I suspect we would have to ditch the Content-Location header, and we'd probably want a custom link relation for performing these create/edit operations that detailed the result/warnings wrapper. This is probably the way I'm leaning at the moment.

 

A third option would be to continue to return a 403 and include enough information to allow the client to remove the offending elements and resubmit the request. This could become tricky in scenarios where the client is automated (a feed ingestion engine, for example) and the validation more complex.

 

Has anybody attempted anything similar and/or have suggestions that might help?

 

Thanks in advance,

 

Jack.

Jack Whelpton
Solution Architect
Direct Line: +44 1223484162

 

Like our Facebook page Facebook
Follow us on Twitter Twitter

**************************************************************************************
Confidentiality: This e-mail and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this e-mail in error please notify the sender immediately and delete this message from your computer without further action. Any views or opinions presented in this email are solely those of the author and do not necessarily represent those of the company. Any dissemination, distribution or copying of this message or any files transmitted with it by an unauthorised recipient is strictly prohibited.
Viruses: This message has been swept for viruses but we cannot guarantee that this e-mail or its attachments are virus free nor accept responsibility for any virus inadvertently transmitted herewith.
**************************************************************************************

Jørn Wildt

unread,
Jan 28, 2015, 9:16:35 AM1/28/15
to api-...@googlegroups.com
Just a few thoughts ...

- You could argue that if you GET /widget/AAA then the same warnings would be there - they would simply state "This widget is not yet complete - do something about it".

- There is nothing inherently wrong about including additional temporary values/properties in a response. Maybe some values are only present when it is full moon, maybe some are only there for certain users - or simply there as long as the resource is in a certain state (like having an invalid model number). The resource representation simply contains the current state of the resource - including warnings and what ever else you can come up with.

- The problem here is to think about actions and their results instead of resources and their state.

- FWITW I have a similar problem with HTTP PATCH with JSON-PATCH documents: I can describe operations on the resource (like "replace value X with Y") but I cannot specify side effects like "... and in addition to all that please register 'XXX' in the log".

/Jørn


--
You received this message because you are subscribed to the Google Groups "API Craft" group.
To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+...@googlegroups.com.
Visit this group at http://groups.google.com/group/api-craft.
For more options, visit https://groups.google.com/d/optout.

Chris Mullins

unread,
Jan 29, 2015, 2:17:48 PM1/29/15
to api-...@googlegroups.com
Hi Jack,

I've worked with API's in the past that offer a "Success with Info" style moniker. Without fail, these API's create customer angst, as developers seldom (Never!) properly code for these cases. 

My opinion, which comes from dealing with such APIs, is that the "Success with Info" scenario should be avoided. Succeed or Fail, as the clarity means devs building against your API's will be happier for it.

Cheers,
Chris

Chris Mullins

unread,
Jan 29, 2015, 3:07:28 PM1/29/15
to api-...@googlegroups.com
Hi Jørn, 

The biggest issue I have with the "Success with Info" pattern is this:

> Maybe some values are only present when it is full moon, maybe 
> some are only there for certain users  

In effect, this means you'll be returning things - once in a great while - that devs have never seen before and more than likely have never tested with. In the best case the code paths through the client code won't be nearly at mature as the mainstream success/fail cases. In the worst cases, you'll break the client application. This leads to low quality offerings built atop your APIs, which ends up making your uses unhappy. 

There is significant literature showing that developers struggle with normal failure cases. Adding "subtle and hard to test" or "subtle and rarely seen" or "surprising" error cases will only compound that problem. 

Cheers,
Chris

Manu Whig

unread,
Feb 8, 2015, 11:34:01 PM2/8/15
to api-...@googlegroups.com
+1

Having hidden or unforeseen side effects like these cause developers major heartburn. If the developer, the consumer of your api, simply choses to ignore the warning and informs the user of their app that the widget was created successfully, it can in turn lead to customer angst when they try to search for the Widget they just created, using the model-number they just supplied.

darrel...@gmail.com

unread,
Feb 9, 2015, 11:27:03 AM2/9/15
to api-...@googlegroups.com
Chris,

You are correct that many developers are not used to coding against these kind of flexible contracts.  There is a long history of strongly typed interfaces between components.  However, IMHO, the solution is not to give up on developers and declare that “they’ll never learn”. 

For distributed systems to work for the long haul they need to be built to evolve over time.  If you don’t build flexibility into interfaces you will face versioning hell.  I am fairly confident in predicting that JSON over HTTP APIs that use explicit versioning to manage change will face a versioning hell in the future that will make Windows DLL Hell look like child’s play.

An interesting compromise that is available in HTTP is the use of the Prefer header with the strict/lenient parameter.  Using this option allows a client to suggest to the server how to process the inbound data.  For scenarios like data imports and other batch type operations, a header of Prefer: lenient might be appropriate.  However for cases where a user is interactively creating something and wants to be assured that all the input data is valid, the client application can use Prefer: strict.

The definition of this Prefer parameter is left intentionally vague so that it can be tailored for the particular situation.

The final suggestion is that HTTP does have a warning header, which traditionally has only been used for intermediaries like caches to report warnings.  However, I see no reason why the use of this header could not be extended to convey other business related warnings.  The advantage being that it keeps the warnings out of the response payload.

Darrel


Sent from Surface

Reply all
Reply to author
Forward
0 new messages