1

Given a resource for which only its subsets of attributes can be edited, {E.g. invoice (resource) with a status (attribute) and paidAmount (attribute)}, in terms of API design, which amongst the following is the better approach:

  • PUT /invoices/{id}/status - here I'm afraid of an attributes explosion which will make the API unusable?
  • PUT /invoices/{id} - here I need to send the whole object just to update single field..
  • PATCH /invoices/{id}/ - here just a set of fields that need to be updated will be sent.

Which way is the best one to go? Or maybe there are some alternative ways?

talonx
  • 2,762
  • 2
  • 23
  • 32
Opal
  • 275
  • 1
  • 2
  • 9

2 Answers2

2

TL;DR I would suggest implementing a combination of the second(PUT /invoices/{id}) and third(PATCH /invoices/{id}/) suggestion.

Let us look at the first part which is the URI. Many standards can exist as to how the uri's can be formed depending upon the guidelines followed by a project or team. However, for simplicity one of the thumb rules that I would prefer to keep is that a given resource end-point should ideally have a matching get end-point' (except if the endpoint ends with an operation name).

To make my point clear, PUT /invoices/{id}/status - this suggestion should only make sense (or make things intuitive for the api consumer) when you also have an equivalent GET /invoices/{id}/status for it, which I believe would not be the case as it will only make your development effort far more cumbersome. If by any chance you do want to selectively expose attributes in 'GET', I would still suggest implementing GraphQL for 'GET' rather than implementing your own standard and going with 'PATCH' for updates. (Also, just a small recommendation, you ideally would want to keep attributes such as status in an invoice as read-only as they represent the state of the invoice and should ideally be changed via some operation-specific endpoints such as POST /invoices/{id}/send rather than through a PUT operation.

Coming towards the other suggestions mentioned, PUT /invoices/{id} and PATCH /invoices/{id}/, the decision is based upon whether the API is exposed internally or externally because otherwise, both are valid HTTP standards.

  • If exposed externally, I would suggest implementing both PUT and PATCH because many of the API consumers might not have relevant support for implementing PATCH or might consider it as a bit too tricky to implement it flawlessly, depending upon the developers they have and in such a scenario you would prefer to give them both the options.
  • If the API is strictly for internal usage, you can in such cases choose to go solely with PATCH to get the benefit of reducing unnecessary payload in your update request.
6harat
  • 243
  • 2
  • 4
1

If you are not allowing a full CRUD style update of the object then I would not have a partial update method either.

Instead have methods which match the operations which require those subset of fields to be updated.

eg. where we want to update the status and paid amount because we have paid the invoice have:

PayInvoice(InvoicePayment payment)

InvoicePayment 
{
    string InvoiceId {get;set;}
    decimal Amount {get;set;}
}

Choose HTTP methods to your required level of RESTFullness

Ewan
  • 70,664
  • 5
  • 76
  • 161