Model-View-Controller (MVC)

The MVC design pattern is the most used pattern for designing API systems. The main idea behind MVC is separated presentation (https://martinfowler.com/eaaDev/SeparatedPresentation.html), where the architect endeavors to make a clear division between domain objects which model the real world and presentation objects which are the visual representation elements (or the GUI). This pattern defines clear responsibilities for each component:

Let's have a look at each component in detail:

  • Model:
    • Manages the application state and exposes data entities
    • Encapsulates business logic that governs that data, such as accessibility rules
    • Responsible for persistence
    • Not coupled with UI or presentation, and can be used with different user interfaces
  • View:
    • Responsible for user interface
    • Handles rendering of information and user actions
    • Not stateful
    • Generally is very configurable with templates
  • Controller:
    • Serves the role of the intermediary between the model and view components
    • Responsible for updating views on changes in the model
    • Responsible for orchestrating model updates based on user interactions
    • Generally hosts business logic around functionality

In traditional web applications, the view consisted mostly of templates that take some parameters, render something like a HTML page, and then send to a dumb client like a browser. However, with the advent of rich clients in modern applications, the view is increasingly embodied on the client side. It is either the mobile app or smart JavaScript code that renders UI elements and interacts with the backend using APIs. The UI code itself often follows MVC pattern variations: one common variation is the Model-View-ViewModel (MVVM) pattern, where the ViewModel is a semantic definition of the user interface, and the view is more concerned with actual GUI/ UX specifics/bindings to a specific UI form factor. 

For designing backend APIs, most languages have support of web frameworks where the key feature is an HTTP router that essentially maps a request URL (or a prefix of the URL) to a handler function—the controller. We already saw how this works in the Gin framework. High performance routers like than in Gin or httprouter (another popular router in Golang) are based on Radix trees (compact prefix trees), and essentially the URL walks through the tree to figure out the handler.

One might wonder why not to use a HashMap for the router; well, to allow for path parameter (for example, /v1/hotels/:id/book). Using the tree to navigate allows us to assign-and-jump URL segments with path parameters to get to the required handler. Generally there is a router instance for each method, for efficient representation of the router.

The controller generally defines logic to understand path/query parameters and interacts with the model. It hosts the main application business logic on how the API handling needs to be done. Generally, a web framework gives a specific format for the controller, so that the developer writing the controller for an API can access context such as the query parameters, the request body, and so on. Sometimes a set of handlers need to do similar things (for example, authorization), and such processing is generally done through middleware in the web framework. The applicable processing is done at the start or the end of each request processing for a specific handler.

The model components define the entities (typically structs) in Golang, the helper get/set methods, the persistence, and the business logic in terms of accessibility and so on. One way of enabling persistence is using Object Relational Models (ORMs), which help in mapping Golang structures into/from how the data is represented in the database. We shall look at ORMs and persistence in more detail in Chapter 8, Modeling Data.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset