4

I'd like some perspective about ways to perform writes using a RESTful API. For this example, assume a Person object:

{
    "id": 1,
    "name": "Example Person",
    "addresses": [
        {
            "id": 11,
        }
    ],
    "friends": [
        {
            "id": 21,
            "name": "John"
        }
    ]    }

There's a /people API that serves up objects like these. You could GET /people/123 to retrieve the above example. What I'm concerned about, though, are writes. Conventionally, updating an object like this via a REST API is done by sending a PATCH or PUT to /people/123 with the new state of the object. However, you could potentially be doing one or many things in your update:

  • Change the person's name
  • Update an existing address
  • Add a new address
  • Remove an address
  • Update an existing friend
  • Add an existing person as a new friend
  • Stop being friends with someone

Each one of these is a different action that may have different logic associated with it. For example, if someone adds you as a friend, you should get a notification about it, whereas adding an address shouldn't generate any kind of notification.

When communicating with a REST API, is there value in sending a list of actions to take instead of just sending the new state of the object and asking the API to figure out what actions the user intended to perform based on that?

Michael
  • 377
  • 1
  • 3
  • 12
  • 1
    REST is resource based. The sample person you have listed is practically not a single resource. It is multiple resources. If you combine them into one resource you end up with the confusion you seem to have. Separate them and everything becomes clearer. – Quality Catalyst Jan 03 '18 at 23:22

5 Answers5

10

Your objects contain lists of other objects. Technically, you deal with many objects, not a single one. Consequently, your JSON result isn't RESTful. REST is based on resources (what you call objects), and you typically isolate them when they they are no composites. So when you call

GET /people/123, that should not deliver the example you have presented. It should deliver the something like this:

{ "id"   : 123,
  "name" : "Example Person" }

That is a proper person resource, nothing more. Friends and addresses would be designed as sub-resources and should be accessed through their own API such as this:

GET /people/{id}/addresses
GET /people/{id}/friends

When someone adds you as a friend, you naturally have an explicit resource call for that. Here's an example:

POST /people/{id}/friends

This POSTcontains in the body the ID of one friend, likely nothing more.

Side note: When you return the list of friends back later, you get only the list of friend IDs and not their details like names. Reason is that a friend is a relationship that you ask for, not the person's details. If you want the person details you'll have to go to the people resource, for example:

GET /people/{friend-id}         [request for one friend]
GET /people?is-friend-of={id}   [request for all friends]

An update of all friends would look like this:

PUT /people/{id}/friends

This PUTcontains in the body the list of all IDs of the friends.

The business logic you need to implement will be very easily linked to these single GET, POST and PUT requests. That should make your business logic hell become clear and easy. You may even find to not needing a PATCH anymore. I have learnt to avoid it whenever possible as it is causing more trouble than it is of help. The RESTful guidance deals with the PATCH verb too vaguely at a detailed level.

I suggest you learn more about what RESTful means and once you have an API that actually is RESTful, you'll be finding it easy to deal with your business logic. Good start: StackOverflow: What is RESTful programming?

Quality Catalyst
  • 6,531
  • 8
  • 38
  • 62
2

What you mean are the business rules, which have to be placed in Business logic layer, client side must NOT care/know about the actions which have to be done on some request. What I assume you should do is create some checking mechanism in BusinessLogic layer which property is being changed and then take some actions(if you need different actions to be done whether you unfriend someone/change name/etc.) according to this check.

1011sophie
  • 237
  • 3
  • 9
2

REST is a protocol-agnostic design technique in distributed systems to decouple clients from servers. Though commonly people call a JSON-based Web API exposed via HTTP that partially adheres to the semantics of the defined operations as RESTful (as with certainty in your case). The problem here is, that the decoupling will only work if all of the constraints a REST architecture imposes are handled properly. These JSON-based Web APIs often return plain application/json based documents that actually contain no semantics for either side and thus require out-of-band information (or a-priori knowledge) on how to handle such documents. Sure, HAL JSON or the XML-based Atom specification help on supporting peers in such an architecture further, though still the document is probably to generic to fulfill the tasks.

Peers that adhere to a REST architecture would ideally negotiate about the representation beforehand and request/send data in the agreed format to the other side. The mime-type is a human-readable, plain-text specification of the syntax and semantics of the delivered document and it is up to the developer of the client/server to integrate this knowledge into the own application (i.e. through a plugin mechanism or as built in support via an imported library).

You therefore have 2 options IMO:

  • Separate parts of resources into own resources (as suggested by @QualityCatalyst) and maybe use a JSON HAL like _embedded field to append additional information to a document
  • Define an own media-type for your documents exchanged which will also contain a description on the semantics of changing specific data

The latter suggestion is for sure the one with the most overhead but this actually would enable decoupling on the long run. Sure, there is still some kind of coupling, though the coupling shifts from client and servers to an intermediary, the media-type. As long as both parties support that mime-type they can exchange documents in that representation and can rely on the outlined semantics of the mime-type definition.

The former one, though, is way easier to achive and therefore preferable in near future. You might start with separating the resources and later on build your own media-types around these.

Community
  • 1
  • 1
Roman Vottner
  • 12,213
  • 5
  • 46
  • 63
0

This kind of function is usually performed by an API gateway (facade design pattern) the client would send the request to a gateway API call and the gateway would call each micro service API

newbie
  • 558
  • 7
  • 12
0

The frontend should not care about what is done with the updated data. It just notices about changes. That’s the idea of decoupled layer architectures. So if an update should trigger sending an E-Mail for example this needs to be done by the backend itself.

you‘d argue that the REST API should not include further business logic and in general that is right. So to seperate concerns your API could provide the CRUD stuff and notice all registered listeners about changes which then send the E-Mail.

Tobias
  • 956
  • 8
  • 16