Question

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.

Était-ce utile?

La solution

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.

Autres conseils

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.

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.

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.

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.

Licencié sous: CC-BY-SA avec attribution
scroll top