38

I'm proposing changes to a very poorly architected software project that suffers from a multitude of problems. At a high level the project utilizes Angular on the front-end and consumes various REST APIs; which is all great (I don't see the need to change our technology or tools). The problem is that the code base is disproportionately larger in the UI than the server-side APIs. Much of the business logic lives in the UI, with the REST APIs being simple CRUD database interfaces to the UI layer.

For example, a POST to customer will create a customer record, while a PUT will modify that customer. Not much more, and not much less. However our business logic is more demanding than that. The general process of creating a customer does quite more than insert 1 database record. It will provision data in other necessary tables, perform certain validations and calculations, etc. I would prefer to make a single POST/PUT call that encapsulates all of this behavior, lightening the load of the consuming client.

So my viewpoint is that this overarching orchestration should live on the server (where we have full control, logs, etc), not the UI, but one counterargument is that this approach would no longer be RESTful. So I am uncertain how to best describe this approach when my recommendation is to continue with the existing technology stack, but implement fundamental shifts in the locations where code belongs.

Ben Harrison
  • 1,183
  • 1
  • 11
  • 12
  • 44
    Confining your API to CRUD calls for the sake of making it "RESTful" is a poor tradeoff. – Robert Harvey Jun 21 '18 at 14:31
  • 1
    Have you considered putting a BFF between your UI and the services? – Esben Skov Pedersen Jun 21 '18 at 16:26
  • 38
    @EsbenSkovPedersen: Best Friend Forever? – Robert Harvey Jun 21 '18 at 16:27
  • 3
    https://samnewman.io/patterns/architectural/bff/ – Esben Skov Pedersen Jun 21 '18 at 16:28
  • 4
    @EsbenSkovPedersen: Ah. The [Gateway pattern](https://martinfowler.com/eaaCatalog/gateway.html), a variation on Adapter. – Robert Harvey Jun 21 '18 at 16:30
  • It is a little unclear from this description if it is the same. The description indicates the gateway lives inside the same process as the clients. A BFF certainly does not. – Esben Skov Pedersen Jun 21 '18 at 16:52
  • @EsbenSkovPedersen: [This kind of gateway](http://microservices.io/patterns/apigateway.html) then, which almost certainly doesn't live in the same process. – Robert Harvey Jun 21 '18 at 16:56
  • Exactly. They also call it both. – Esben Skov Pedersen Jun 21 '18 at 16:58
  • 1
    @EsbenSkovPedersen: Well, the author of that post makes a distinction between a Gateway (a single-point entry for all clients), and a Backend-for-Frontend (a separate "gateway" for each "kind" of client). – Robert Harvey Jun 21 '18 at 16:59
  • 5
    Instead of worrying about whether your service conforms to REST (iirc, almost none do), I'd worry more about conforming to the [HTTP spec](https://tools.ietf.org/html/rfc7231). Most api's I've worked with also don't conform the the spec, but it's a more achievable and worthwhile goal imo. – aaaaaa Jun 21 '18 at 19:17
  • 7
    @aaaaaa, the reason almost no services conform to REST is that nobody can decide on what REST is. The only point of agreement I've found is "everyone else is doing it wrong". – Mark Jun 21 '18 at 21:04
  • 1
    @Mark - I thought it was clear Fielding defined REST in his dissertation, and noone conforms to that. – aaaaaa Jun 22 '18 at 00:19
  • How about considering GraphQL? – Thomas Jun 22 '18 at 07:03
  • 1
    What's the business value of your API being RESTful the way you define it? How much money has that made you so far? – RemcoGerlich Jun 22 '18 at 08:19
  • 16
    - "How to describe an architectural shift that intentionally breaks REST standards?" - **disRESTpect**. (*Sorry for an unprofessional comment, it was stronger than me.*) – luk32 Jun 22 '18 at 10:56
  • 3
    You need to ask: What are you gaining from REST at all? I believe many projects gain exactly zero from using a REST style API. REST is a rather incredible fad where in some instances otherwise smart people do not realize they gain nothing from it but pain. – usr Jun 22 '18 at 15:43
  • @luk32 I see you have the farce. – Wayne Werner Jun 22 '18 at 21:38
  • 1
    @usr is right. I was about saying the same. I have seen countless attempts to use REST for reasons like "everybody does it" or "it is modern style" or something similar. Let me put it simple: Coolness is not an adequate reason for architectural decisions. And while we're at it: "I don't know anything else" isn't either. There are plenty of good and modern alternatives and approaches. Ask yourself what value would be missed if it were not REST, but sth. else? What exactly does REST add to the solution, that other alternatives don't? – JensG Jun 23 '18 at 09:36
  • 1
    @JensG I think it's a fad and lack of reflection in part as you point out. But also people sometimes want JSON over HTTP (which is OK to use) and then erroneously jump to REST. Maybe that's another mental failure mode. I am continuously amazed by the amount of group think present in the developer community. Developers are supposed to be these emotionless, rational people and then this stuff happens over and over! Total #fail causing enormous damages to the company. – usr Jun 23 '18 at 10:56
  • 1
    `my viewpoint is that this overarching orchestration should live on the server (where we have full control, logs, etc), not the UI, but one counterargument is that this approach would no longer be RESTful` why not? What REST has to do with where the business/logic belongs to? Is it because the server might become stateful? If yes, keep the state on the client side :-). Clients can store data too. Call It cache, call it storage, session or cookies. – Laiv Jun 23 '18 at 17:45

5 Answers5

50

I am uncertain how to best describe this approach when my recommendation is to continue with the existing technology stack, but implement fundamental shifts in the locations where code belongs.

Service oriented architecture.

You are proposing to redesign your system so that your business rules and your data are in the same place. That's effectively the definition of a service; see Udi Dahan's talk on Finding Service Boundaries.

Sidebar: as noted by Eric, this has nothing to do with "REST". There is absolutely no reason that you can't put a REST API (which is to say, an API that satisfies the constraints of the REST architectural style) in front of your service. But that may not be obvious to people who understand REST to mean a mapping of database operations to HTTP methods.

It may, or may not, be worth investing in changing your audience's understanding of REST.

VoiceOfUnreason
  • 32,131
  • 2
  • 42
  • 79
  • 32
    Nor may it be worth investing in REST at all. If you read Roy Fielding's dissertation (or [How I explained REST to my wife](http://www.looah.com/source/view/2284)), the true purpose of REST is to *provide a canonical representation for resources on the Internet, so that disparate machines across the internet would have a standard way to manipulate those resources.* A privately-owned application may not even need this capability. – Robert Harvey Jun 21 '18 at 17:28
30

REST is not CRUD. That "counterargument" is based on a fundamentally flawed understanding of what REST is. I haven't seen anything in your post that indicates your change would make your API any more or less RESTful.

Eric Stein
  • 3,492
  • 12
  • 19
  • 6
    Well, no, it's not a perfect mapping to CRUD, but it does walk and talk and sing very much like CRUD, at least in the way most people interpret it. – Robert Harvey Jun 21 '18 at 14:29
  • 11
    @RobertHarvey I think it's that (mis)understanding that is the problem here. – JimmyJames Jun 21 '18 at 16:15
  • 4
    @JimmyJames: It's a pervasive misunderstanding. There's a strong drive to make things "restful" when most folks don't even understand what the benefits are or how those benefits would apply to them. – Robert Harvey Jun 21 '18 at 16:26
  • 2
    @RobertHarvey I agree. Regardless of how many people believe that, it is incorrect. Maybe I don't understand the point you are trying to make. – JimmyJames Jun 21 '18 at 16:33
  • 1
    @JimmyJames: We're cogitating about the precise definition of REST, when the real problem is the inability of some developers to make a *value judgement.* You can't meaningfully evaluate the viability of a principle, architecture or technique without also evaluating its relative benefits or drawbacks within the context of your own project, and debating word definitions won't get you any closer. – Robert Harvey Jun 21 '18 at 16:36
  • 4
    @RobertHarvey I think you are saying that if doing it the wrong way is REST, then REST should not be a goal. OK but the way I see it, calling this 'not REST' is bullshit and I'm a big proponent of calling bullshit on bullshiters. [Words need a commonly understood meaning to be useful.](https://www.bartleby.com/73/2019.html) – JimmyJames Jun 21 '18 at 17:11
  • @JimmyJames: Of course. But if enough people believe in that misunderstanding, it will eventually become the new "commonly-understood" meaning. See https://en.wikipedia.org/wiki/Begging_the_question: *"In modern vernacular usage, "begging the question" is frequently used to mean "raising the question" or "dodging the question". In contexts that demand strict adherence to a technical definition of the term, many consider these usages incorrect."* – Robert Harvey Jun 21 '18 at 17:15
  • 5
    @RobertHarvey Granted but that won't happen as long as there are enough people who are willing correct these misuses of the term. I'm not ready to throw in the towel. – JimmyJames Jun 21 '18 at 17:25
26

One more thing to keep in mind is the following... Not validating your business rules server side, means you implicitly trust anything that comes in, through say a POST request, is valid.

Meaning that for example, while your angular application might check if the customer has a valid age range and ensures that legitimate users get the correct feedback, anyone that knows the url to your api can do a POST request containing some non-legitimate values which would no longer be validated.

So my suggestion would be to move your business rules to the API, let it validate the input and return appropriate errors (or perhaps just codes indicating what went wrong) in the body of the response. Those codes can than be used by your front-end application to indicate what went wrong.

mrsmn
  • 410
  • 3
  • 6
  • 6
    This is by far the most useful answer here: The API is the attack surface, not the input to the client. Any API request can be spoofed. Thus, anything that can be done with the pure API is what a talentless, malicious script kiddie can do. The client software may be used to provide a better user experience, but it is the server that needs to enforce the rules. – cmaster - reinstate monica Jun 22 '18 at 12:20
11

To add to the other good answers here:

Your interface, REST or otherwise, should not be constrained based on some sort of assumptions around implementation details. This is completely antithetical to the notion of services as an abstraction layer.

One of the main benefits to using services is that implementation details can be changed without the clients having to do anything. From what you have described, it sounds like there is no real abstraction layer. The details of the implementation have been exposed via HTTP. Nothing about REST says that is necessary, helpful, or desirable. In fact, I think I could argue certain parts of the REST definition to mean that this is in fact, a non-RESTful implementation.

What you are suggesting is how a proper service layer should be designed. If someone is telling you that you can't do it because it's not RESTful, that's unfortunate. You can be assured that someone who tells you that knows little to nothing about REST.

Based on your question, you have a resource called customer. Anything and everything required to create a valid customer resource can and should be handled in a POST to the customer base resource (or alternately/optionally in a PUT to a specific customer resource, if it doesn't exist.) REST says nothing about how many database records you need to create on a given call. As Colin Young commented, there doesn't need to be a database at all, it's entirely irrelevant how services are implemented from a REST perspective.

JimmyJames
  • 24,682
  • 2
  • 50
  • 92
  • 4
    REST says nothing about database records, let alone how many. I could create a REST service that controlled a water valve, and exposing a water valve, water supply and tank level resources. You _could_ argue the physical objects themselves are a "database" buts that's stretching things a bit. – Colin Young Jun 22 '18 at 13:31
  • @ColinYoung Yes, thank you for helping to clarify. – JimmyJames Jun 22 '18 at 14:37
3

There are some good answers here, but I'm not sure that they will help you convince your coworkers. As many have pointed out, what you are suggesting is not a shift away from RESTful design, and I think that is key to getting them on board with your proposal.

REST is not about making sure your API only allows storing and retrieving data. Rather, it is concerned with modeling actions as resources. Your API should enable actions to be taken (it is an Application Programming Interface, after all). The question is how to model those actions.

Rather than coming up with a term, examples are probably the best way to explain this to your coworkers. This way you can show how they're doing it now, what problems this causes, a solution that solves the problem, and how it still remains RESTful.

Let's look at your Customer object.

Problem:

The UI POSTs a Customer, but subsequent tables have not yet been updated. What if one of the subsequent calls fails because of an error in your UI code (or misbehaving browser plugin, etc)? Now your data is in an inconsistent state. It could even be a state that breaks other parts of your API or UI, not to mention that it is simply invalid. How do you recover? You would have to test for every possible state to be sure this wouldn't break something, but it would be tough to know what is possible.

Solution:

Make an API endpoint to create customers. You know you don't want to have a "/customer/create" or even "/create-customer" endpoint, because create is a verb and would violate REST. So nounify it. "/customer-creation" could work. Now when you POST your CustomerCreation object, it will send all needed fields for a customer to be fully created. The endpoint will ensure that the data is complete and valid (returning a 400 or something if it fails validation), and may persist all within a single db transaction, for example.

If you also need an endpoint to GET /customer objects, that's fine. You can have both. The trick is to create endpoints that serve the needs of consumers.

Advantages:

  1. You guarantee that you won't end up with bad state
  2. It's actually easier on the UI devs if they don't have to "know" ordering of requests, validation concerns, etc
  3. It's not as chatty of an API, reducing latency of network requests
  4. It's easier to test and conceptualize scenarios (missing/malformed pieces of data from the UI aren't spread across requests, some of which might fail)
  5. It allows better encapsulation of business logic
  6. Generally makes security easier (because business and orchestration logic in UI can be modified by users)
  7. Will likely reduce logic duplication (more likely you'll have 2+ consumers of an API than 2+ APIs that give access to the same data)
  8. Still 100% RESTful

Disadvantages:

  1. It's potentially more work for the backend dev (but may not be in the long run)

It may be difficult for people to understand this paradigm and what is good about it if they haven't tried it out. Hopefully you can help them see by using an example from your own code.

My own experience is that once the devs on my team started implementing this strategy, they almost immediately saw the benefits.

Further Study:

This article from thoughtworks really helped me get the idea of modeling actions as objects using practical examples: https://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling

I would also suggest reading up on CQRS and Event Sourcing as they are concerned precisely with this sort of thing (i.e. divorcing your API from the actual persistence logic). I don't know how willing your coworkers would be to read this sort of thing, but it may give you more clarity and help you explain it to them.

Planky
  • 138
  • 4
  • "*because create is a verb and would violate REST*" -- Absolutely correct. In other words, it would then be the 47.258.346th approach to run "**RPC over REST**". Which is something that I would attribute "unnatural" at least, because it misuses and misrepresents RESTful approaches (they do have their use cases, but RPC is not one of them) and also tends to be inefficient. – JensG Jun 23 '18 at 09:40