Home > Net >  How to build a DRY Laravel resource API?
How to build a DRY Laravel resource API?

Time:09-21

I’m trying to build a resource API with Laravel. It appears that the approach taken by most is to:

  • Create a route for each resource
  • Create a controller for each resource
  • CRUD logic for each resource either in the controller or deferred to a service for each resource

This seems fine if you’ve only got a couple of resources otherwise you are repeating most of code.

Is there a reason why you wouldn’t create a single catchall route, with a single controller, with a CRUD service that could perform logic whatever the resource?

I appreciate this could be considered an opinionated question, so I am looking for the reasons why either approach would or wouldn’t be taken, or, methods to DRY up the first approach.

Many thanks to any responders.

CodePudding user response:

DRY is just one of many design principles and as with all principles, and paradigms, its use comes with pros and cons.

Typically individual controllers and routes are defined for resources because the resources and business logic associated with a resource differs in some way (properties, validation and functions etc.). If we put all the functionality for our resources in a single controller simply to avoid the management of additional routes and controllers, we would have a Frankenstein's Monster of a controller containing logic for determining which resource we're working with and how to process the incoming request, marshalling of data between services and the eventual response. Testing would also be a nightmare task.

Therefore it makes sense to seperate out each resource with its unique processing requirements (the 'S' in SOLID) into individual routes and controllers, encapsulating their uniquire requirements within. This also improves the codes maintainability and testing.

Ask yourself this, if you can process all incoming requests for your resources in a single route/controller without the requirement for lots of conditionals to determine the resource you're working with, they can be processed by the same validation and business logic etc., are they truely different resources?

An approach that is commonly taken for logic that is reused throughout a system is to create a service and inject it into your controller using dependency injection via the service container. You might want to consider going down this route instead.

CodePudding user response:

I agree that there is some repetitive code, that's how I see the problem's solution:

The purpose of an abstract class is to provide a common definition of a base class that multiple derived classes can share.

We can use an abstract class in order to share crud logic between the resources.

  • create()
  • update()
  • delete()

An abstract class is mostly used to provide a base for subclasses to extend and implement the abstract methods and override or use the implemented methods in abstract class.

We can define some abstract methods that will be implemented in subclasses (now in my mind comes only one method but I am sure there will appear more on the fly).

  • getModel() - all the subclasses will show wich model the abstract class should work with

What are the steps?

  1. Create an abstract class BaseResourceController that will extend Controller

    • it will take responsibility for crud functionality of a Model (we don't know the model yet)
    • it will define abstract methods to ensure we will implement them in all the subclasses (ex. getModel())
  2. Create MyResourceController that will extend BaseResourceController

    • it will take care of abstract methods (ex. getModel())

Conclusion

Of course, as I already mentioned there would be a lot of functions like getModel() in all the subclasses MyResourceController (ex: to show validation rules, showing which fields to update, showing who is authorized, so on and so far).

BaseResourceController may get a bit complex if you want to make it work for all the cases (beside crud functionality you can write down validation, authorization, some relationships update here too).

Also, you will still need to define the routes to point to your MyResourceController.

I think this response may create you an overall idea about how to unload some of the logic in abstract clases and avoid code repetition and then you can decide if it is worthing it or not.

  • Related