5

I am working on a RESTful, resource-based, API and I have a large entity (an account) with a lot of properties (30, we'll say). The account has a couple of properties that can be changed...

  1. Name: This actually submits a request (e-mail) for a person to confirm the identity and they use a separate system to update the name.

  2. Target Savings Amount: It's just a number that the client can update to be whatever they want.

So, here's my thoughts were, and why I don't like them:

1. Merge PATCH

  • PATCH .../account/{id}

I would take an account entity in the patch body and update what has changed... which in this case can only be 2 properties (name/savings-target) and 422 any other changes.

  • I like it because you can GET>Modify>PATCH very seamlessly.
  • I don't like it because of such a small change surface for a merge patch doesn't make a tonne of sense. Updating name and savings-target at the same time ends up in an ambiguous response as the name update doesn't take effect.

2. POST updates

  • POST .../account/{id}/updates/name?value=test
  • POST .../account/{id}/updates/savings-target?value=123.00

Treat updates as entities and post new ones to the account.

  • I like it because it's consistent, clean, allows me to handle responses differently (name update returns some kind of deferred response like a 204 or something, and a 200 for savings-target).
  • I don't like it because it feels like it's falling into an RPC-esque API and I'm trying to avoid that. Treating updates as entities seems janky as there's no updates to GET. Also, if I do end up adding more fields that can be updated, this gets ugly really fast.

3. Actual Update Entities

  • POST .../account/{id}/updates
    • takes a body that is probably just a key/value pair and returns 303 referring to to...
  • GET .../account/{id}/updates/{update-id}
  • GET .../account/{id}/updates
    • also a valid endpoint that could return all of the updates created for this account entity

Basically, 2, but I have actual entities for updates a-la CQRS. The update entity (for lack of a better name, at the moment) has a status indicating whether the change has been completed.

  • I like it because it models the changes most accurately, I think.
  • I don't like it because it's a heavyweight solution. For trivial changes like the savings-target, I can update the account entity and complete the update entity immediately which is fine, but for something like name, there's no system in place to actually call back to the update entity to complete it.

It seems like a boat load of overkill, and a lot of work just to have a cleaner API. I also don't have the throughput concerns that normally warrant that type of architecture.

4. JSON Patch

As seen here

  • I like it because it's a standard and is relatively easy to implement.
  • I don't like it because it goes against the resource-based focus of the API that I'm developing (this is a requirement from the business...).

Help

I'm not constrained to these 4 choices, but they're the best ones I could think of. I'm leaning towards 2 and am looking to be either validated, or given an experience-based solution from someone else who's encountered a similar situation.

0

1 Answer 1

3

Consider using micro endpoints. You can expose the following additional endpoints:

/accounts/{id}/name
/accounts/{id}/savings-target

You can enable POST on the name and PUT on the target savings amount. You don't even need to support JSON on the endpoints. You can POST to name a simple string (email address), and you can PUT the new target amount. The account endpoint response can still include the name and savings-target properties.

4
  • I had thought of that and the concern I had was that name/savings-target are not entities within the domain (they're just properties on the account entity) but are being modeled that way using endpoints like this. May 21, 2018 at 20:16
  • @StevenEvers ReSTful APIs don't expose entities. They expose "resources". A resource can be whatever you need it to be.
    – Eric Stein
    May 21, 2018 at 23:27
  • Fair enough, I misspoke. name/savings-target are not resources, and if I model them as such then it feels like I'm so loosely defining "resources" that the term loses value for the purpose of designing the API, and "everything's a resource and it's all just endpoints" again. I might be wrong. What do you think? May 24, 2018 at 18:01
  • This seems reasonable. What if I want to update a field for all resources which satisfy some predicate? For ex, change status of all active orders. Would the following make sense? PUT /orders/active/status
    – goedi
    Nov 20, 2019 at 12:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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