Node/Express/Mongoose structure

You should see middleware as a step in your API and controllers as the entity that will actually respond to the requests

  • Services: Make our code cleaner by encapsulating business logic operations into functions that middleware and controllers can call.
  • Middleware will validate prerequisite conditions before Express.js calls the appropriate controller function.
  • Controllers that use services to process the request before finally sending a response to the requester.
  • Models that describe our data and aid in compile-time checks.

Controllers, take HTTP requests and decide which service it should go to. It can break the work up and send to different services. A controllers takes data from Express (or any other framework) and checks/validates before passing off to a service. A controller does not have any business logic/database calls etc, more like a manger while the services are like workers.

Services, receive the data they need from the controller. Has the logic/work, makes database calls etc. Returns completed task to the controller.

In back end web applications, controllers handle incoming requests and hand off/delegate valid requests to the service layer.

There’s two schools of thought really, and you’re seeing both of them in the comments, and it almost entirely comes down to semantics from different frameworks.

  • some see controllers as synonymous with a router route (or adapter)
  • some see controllers as synonymous with application logic
  • if there is something called a service layer, it typically means application logic
  • therefore some people call the application logic layer controllers, some call it services

In the end you have three layers:

  • ingress adapters (the code in your http router)
  • application logic (the code that enforces business rules and process flow)
  • infrastructure code (i.e. repositories, for data access, storage, messaging, etc)

One side of the camp would see:

  • Controller
  • Service
  • Infrastructure (db/messaging)

Others would see:

  • Router
  • Controller
  • Infrastructure (db/messaging)

Call these whatever you want, this is your typical three layer architecture. Some abstract even further to four layers if you’re working on a large enterprise app that has more cross-cutting concerns or code reuse.

I highly recommend reading the DDD book in its entirety if you are getting into backend development. It’ll save you a world of pain and prevent spaghetti. Also consider using a DI library - I quite like Awilix.

Stick to the single responsibility principle to keep things well separated. Make your routers/controllers handle work specifically related to handling requests, and sending responses. Make your infrastructure layer specifically about connecting to infra like databases by handling their configuration. Make your application logic layer in the middle specific to app / business logic needs, it should feel like plugging things together and doing basic if/else logic.