1. 30
  1.  

  2. 9

    These few HTTP verbs

    You can have as many HTTP verbs as you want.

    HTTP actually is an RPC system with verbs as the method names. REST, though, is about switching API design away from verbs and towards nouns. The problem outlined in this article is that the author is still designing verb-first RPC APIs but then trying to shoehorn those into “REST” – which is of course painful.

    1. 7
      1. 9

        As it turns out, some applications aren’t exclusively CRUD operations on JSON objects. As soon as you have one vaguely interesting operation that works on more than one object type, REST falls apart. In other words, every interesting API will be “shoehorned” into REST.

        1. 2

          REST is not designed for CRUD operations specifically. It is based around the idea of performing some ACTION against some kind of ENTITY, and if you are running into issues like these you probably don’t have very well defined entities or you are trying to wedge everything into one bucket instead of knowing where to draw the lines.

          1. 6

            Okay but what do you do when you need to perform some ACTION against three kinds of ENTITIES? It just doesn’t work.

            And that isn’t even true. REST is about Transfering REpresentation State, i.e. CRUD. Where do you see “perform arbitrary actions on entities” in “transfer representation state”?

            1. 3

              I can think of a few options:

              1. Chain the three actions so they have to be performed in order, such as with a multi-page form. Mastadon’s API requires that photos be uploaded before they’re used in a message.
              2. Create a unified entity that wraps all three. Old-style multipart file uploads do this in a single request.
              3. Model a collection that provides space for three sub-resources. This SO answer explains it succinctly.

              This is not challenging at all. REST can handle all kinds of applications just fine, and the decisions required to make it work are exactly the same ones you’ll be making in your own server code. You might have to do some up-front modeling work to adapt your application model to REST to save your end-users a headache if they’re already confident with other APIs, if it’s a worthwhile trade-off for you. It’s hardly an example of REST falling apart!

              1. 7

                Cherry picking a few obvious examples is not particularly convincing.

                But if it’s “not challenging at all” then maybe you can solve this for me. I have a REST API that handles task scheduling for multiple teams. Tasks have different interactions, A blocks B, B can only be done Tuesday-Thursday, C can only be done on weekends but not concurrently with A or B, but doesn’t depend on either of them being done.

                Now we need to reschedule A. PUT /task/A {“start_time”: “new time”}. This will reflow the entire schedule and require user approval of changes. So how do I make this RESTful? In practice, possibly hundreds of entities are affected, and that’s not an infrequent edge case.

                Hint, things that will not work:

                • action chain, this would potentially involve hundreds of RPCs and would need substantial business logic on the client side, and we must support 4 client platforms
                • unified entity, this is just the entire project
                • a virtual reschedule operation “resource”, this is just an RPC, if you suggest this you have failed
                1. 6

                  Interesting problem! If I’m understanding correctly, you want to make it possible for Task A to be updated, but you need the result to be provisional in some form so that the implications can be approved? Does the application do the reflow on its own and then ask for a thumbs-up?

                  Sounds like a branching operation, since you have that user approval in the middle. So, the client might POST a proposed new Task A and get a 303 response with changes for approval: “Had to move B to Wednesday to fit A, is this okay?”. Nothing would actually change in the master schedule until the user had followed the chain to approve the various constraint resolutions. The model (and associated resources) could look a lot like Git trees, with alternative branching histories of different options that later get merged depending on conflicts.

                  If you’d rather require the user to resolve conflicts themselves ahead of time, the client might PUT a change to Task A and get a 409 response with a list of conflicting tasks. Then it’d be up to the user to figure out that moving Task B to Wednesday will make room for Task A, which would be a bummer for the user but would save the effort of attempting to represent alternative possibilities.

                  In both cases, the client app is following prompts and links as it moves between requests and responses. The resources change along the way depending on whether it’s the user or the application that’s tracking alternative states, but the client need only walk the API piece by piece the same way you can make complex branching histories on Github by typing into boxes and pressing buttons on web pages.

                  1. 6

                    Good effort. We considered of all of those ideas in some form but ultimately just gave up on REST.

                    you want to make it possible for Task A to be updated, but you need the result to be provisional in some form so that the implications can be approved? Does the application do the reflow on its own and then ask for a thumbs-up?

                    Yes and yes. Except potentially the client will send a batch of edits to update, create, and delete multiple tasks. That initially looked like a POST to our /tasks endpoint with a list of operations. I don’t think that’s particularly RESTful. We ended up with an RPC API that allowed you to submit multiple RPCs as a transaction. That made the change endpoints less special case-y, since the batched RPCs and regular RPCs were the same code.

                    In both cases, the client app is following prompts and links as it moves between requests and responses.

                    This would generate far too many requests. We really wanted to keep it to 1 request, 1 response per save attempt.

                    Unfortunately, in order for the conflicts to be meaningfully displayed, the entire result of the change had to be returned, which means returning every changed entity. We ended up returning property-level diffs of every entity, allowing the user to reflow manually, update, and get a new list of diffs from their previous attempt. Every request ended up being really stateful, for this particular UI action and for most other write UI actions.

                    You’re spot on that the model looked like git trees, the application ended up like a git repo: a user’s entire project cached locally, and most updates done with sync-from-revision-N style RPCs. We didn’t think it would be valuable to have git-like resources representing change sets, since the change sets were never actually stored in our data model. It makes more sense for e.g. GitHub when those change sets are the data model. And I definitely don’t think this makes any sense as a general purpose way to handle complex changes in REST applications. IMO it’s pretending you’re RESTful but really just placing a RESTful transaction layer under your application, rather than actually writing your application in a RESTful way.

                    It’s not like I hate REST or anything. It works great for applications where you really are transferring representation state around. But for us, the client effectively had no say in what the data would look like, it could only perform actions and get the new state. Modeling that as proposed changes to state just did not work, especially when faced with concurrent modification. Many of our actions potentially affected multiple entities based on complex business logic, and it would just be too much work for the client to perform even some of that logic and submit a new state that made any sense.

                    So I guess my real problem isn’t with multiple entities, it’s that REST pushes business logic into client side code, and that logic can become exponentially more complicated as more and more entities get involved. For APIs meant to be used by third parties to create new functionality, the logic is supposed to be in the client side code, and REST provides a lot of flexibility. But for your own application code you have the option of building the exact operations you want directly into the server. If your application is all about navigating through different resources, and extremely reusable resources like photos, REST would work just fine even for working on multiple entities as you described. Not all applications work like that.

      2. 8

        SOAP became a thing in 1998. REST was being designed around that time as well. It’s not a “new SOAP” - it’s just better than SOAP because it is based on how HTTP actually works instead of throwing a ton of crap on top of it.

        1. 7

          What a strange article. Author lists every common benefit of REST and just disagrees with each one while providing no new information. “No it isn’t… no it doesn’t… that’s not true… nope, not that either.”

          If you want to design an RPC API and stick all your semantics into POST bodies talking to a single “/do” endpoint, fine. Personally, I much prefer to interact with a well-designed REST API like Github’s with its RFC-compliant URL templates, header-driven paging, cache semantics, and more.

          1. 4

            Have you used Github’s GraphQL API yet? Personally, I’ve found using it to be a breath of fresh air in comparison to their REST API, which was easily one of the best REST APIs I’ve used and leagues ahead of most implementations. Give it a go, the RPC-like mutations are particularly wonderful.

            1. 1

              Compliant with which RFC, exactly?

              1. 1

                5988 and 6570 were the two I had in mind.

            2. 1

              I think this article makes some fairly good points, and I’ll warrant that I haven’t read it in its entirety, but I think one of the reasons the world abandoned SOAP and adopted REST is that outside of the Java and .Net worlds, the tooling was abysmal until far, far too late (and in some cases is still abysmal today).

              So whether or not SOAP was the shining bastion of logical purity the author describes depends very heavily on the platforms and SDKs being used.

              When people feel pain, they reject the tools that cause them pain and find new ones that hurt less. For the simple use cases, REST hurts a LOT less with crappy tooling.