سؤال

This may seem like an odd question but it's something I've yet to find a "proper" answer for. I've tried googling but I don't get anything useful (maybe I'm looking for the wrong terms).

I'm attending a couple of classes where I'm building Web APIs, one using Spring Boot and the other using NodeJS (with Express), and we've been told to use logical layers like the "Service Layer" or the "Data Layer" but I haven't yet fully understood which responsibilities should belong to whom.

For instance, in the Spring project, I get a POST request and my handler receives a DTO and then I need to perform these steps:

  • Transform the DTO into a Model object
  • Validate the model according to the business rules
    • Throw an exception if validaton fails and return an error response
  • Save the model to the database
  • Return an OK response

I'm having a hard time understanding to which "logical" layers each step belongs to (since I don't fully understand the layering yet), specially who handles the errors and how. Like, if validation fails due to business rules the exception I throw shouldn't know about HTTP but then whose job is it to catch it and map into a proper HTTP error?

Thanks for the help.

هل كانت مفيدة؟

المحلول

Data layer handles persisted data. Sometimes called the persistence layer. So that would include reading from a database, saving your model to the database and so on. So all database accesses are done through the data layer. Service layer will use the data layer to access and modify data stored in the database.

Service layer and both data layer could handle validation but usually validation is done in the service layer because for most entities/models the validation logic stays the same for different persistence methods such as a database or a file. For complex validation, the service layer could call validate on a separate Validator class.

If you want to respond with specific status codes you can add @ResponseStatus annotation to an exception with the status code that you intend to respond to the request and then let the uncaught exception propagate for the framework to turn it into a http response.

@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public class YourException extends RuntimeException {

When native uncaught exceptions are thrown you can let the framework handle them. That will result in status 500 response.

So for your steps i would implement them like this:

  • Service layer: Transform the DTO into a Model object
  • Service layer: Validate the model according to the business rules
  • Service layer: Throw an exception if validaton fails and return an error response (let the framework handle the error response part)
  • Data layer: Save the model to the database
  • Service layer: Return an OK response (return void and let the framework handle the success response)

نصائح أخرى

In general, you don't need to do any specific mapping, as it is performed directly by the framework you use.

For instance, in ASP.NET MVC, you'll just specify the validation rules, and let the framework do the rest, that is to check whether the input is valid, and if not, return the appropriate HTTP response, with the appropriate MIME type and appropriate HTTP status code.

Similarly, if you have an unexpected situation on the server, for instance you try to save a file, but an exception occurs because the RAID controller encountered an error and switched all disks to read-only mode, then you just let the exception propagate to the framework which will return HTTP 500 to the caller.

This has an additional benefit over handling exceptions yourself. You can easily add behavior, such as logging, or custom error pages.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى softwareengineering.stackexchange
scroll top