Why do we need controllers?

MVC is the most popular architectural pattern which split your web application into three layers caller Model View Controller.

Model: Model is the one which connects to DB and provide the necessary data for your application. In Simple term Model is the data access layer (DAL) which has all database related functionality.

View: View is nothing but the actual view you see on the monitor screen. In simple term view is the page which may contains HTML, CSS and JavaScript which gets rendered on the browser.

Controller: Controller is the one which actually controls the application. Whenever we send a request to any page, a specific controller gets triggered and redirect the request to specific model to get data and send those data back to a specific view which gets rendered with the data. Controllers has the business logic mostly.

Our business is becoming more and more complicated, and the MVC pattern is just too limited to do what our system needs to do.  Let us see an example if we have a database that contains some tables such as company table, department table and employee table. There are dependencies between these three tables. If we want to delete a company, we must first delete all of employees from the employee table and delete all departments of this company from the department table.

Suppose we have three APIs is delete specified employee, delete specified department, delete specified company, respectively. To implement these APIs, we must first implement delete specified employee and delete specified department, but we must also implement delete specified employee and delete specified department in the third API again.  We would add a lot of redundant code to our web application.

So, in this case, we should add a service layer to our web application. We must first implement employee service and department service. We implement company service by calling the employee service and department service that can reduce a lot of redundant code.

The service layer is more suitable for more and more complicated business, it may contain some complicated operation using multiple tables, sending message to MQ or calling some api of other services, etc.

We need to add a new layer that is named Validation layer now because we know all parameters of the request are not secure.  Each and every request should validate before processing it whether an Action method is GET, POST, PUT or DELETE. Validation is a very essential part of Web APIs implementation. Regardless of what kind of Web APIs you are building, the bottom line is validating a request before processing it.

Microservices are an architectural and organizational approach to software development where software is composed of small independent services that communicate over well-defined APIs. These services are owned by small, self-contained teams.

Microservices architectures make applications easier to scale and faster to develop, enabling innovation and accelerating time-to-market for new features.

With a microservices architecture, an application is built as independent components that run each application process as a service. These services communicate via a well-defined interface using lightweight APIs. Services are built for business capabilities and each service performs a single function. Because they are independently run, each service can be updated, deployed, and scaled to meet demand for specific functions of an application.

Let us see an example:

@app.route('/account', methods=['PUT'])
def sign_in():
    account_service = AccountService()
    username = request.form.get("username")
    password = request.form.get("password")
    result = account_service.sign_in(username, password)
    return jsonify({"result": result})

The ML models or machine learning models have been widely applied across various industries for a particular business purpose in recent years and this trend is expected to continue in the future as well. As a result, a new set of challenges has emerged.

We usually use deep learning models as independent service and deployed in a cluster with other business services that are also called "Model-as-a-Service". So maybe we just have a few APIs in this model service to call the model to predict something or embed something.​

To sum up, we split the responsibility of the controller between the service layer and the validation layer. Furthermore, our web application just needs to implement a few lightweight APIs with the development of Microservices.  Admittedly, MVC is the most popular architectural pattern, but why do we need controllers because these APIs in a controller just need to implement register it have what APIs in web server and provide service by calling service layer or render a page. We should not manually make some controllers, integrate with gRPC and write APIs documents for just a few APIs that waste a lot of time.

If we had a framework that via configuration files like OpenAPI Initiative of using markup language(such as yaml, json) could automatically register routes, call some service from service layer, render some pages.  We can delete the controller layer in our architectural pattern.

The OpenAPI Initiative (OAI) was created by a consortium of forward-looking industry experts who recognize the immense value of standardizing on how APIs are described. As an open governance structure under the Linux Foundation, the OAI is focused on creating, evolving and promoting a vendor neutral description format. The OpenAPI Specification was originally based on the Swagger Specification, donated by SmartBear Software.

I don't really like the OpenAPI Initiative because it's complicated and hard to learn. It's acceptable if it's generated by code, but it's a nightmare if you have to write the configuration by yourself. Probably, we need a more simple specification for standardizing how APIs are described. So we present a new specification,  let us see an example:

specificationVersion: v1
title: Sample Store App
description: This is a sample server for a store.
contact:
  name: API Support
  url: http://www.example.com/support
  email: [email protected]
license:
  name: Apache 2.0
  url: http://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.1
externalDocs: https://externalDocs/
servers:
- name: aAPIServer
  url: https://development/v1
  description: Development server
- name: bAPIServer
  url: https://staging/v1
  description: Staging server
- name: cAPIServer
  url: https://production/v1
  description: Production server

# If onlyRemoteServcie is true, only the remote call needs to be authenticated. You can declare the authentication method.

authentication:
  enable: true
  onlyRemoteServcie: true
  type: password
  password: 123456

# After the declaration, the service layer can be directly called remotely using the name.

remoteServices:
  - name: "remoteServiceA"
    autoDiscoveryUrl: ""
    remoteServiceName: ""
    authentication:
        type: password
        password: 123456

tags:
  - name: beta
    description: Be careful!

resources:
  - version: 1
    name: signin
    url: /api/accout
    method: POST
    cache: true
    grpc: true
    http: true
    https: true
    remoteService: false
    category:
      - account
    tags:
      - beta
    deprecated: false
    externalDocs: https://externalDocs/
    validators:
      - TestValidator
    parameters:
      - name: username
        in: query
        description: This is your username.
        default: testUsername
        type: string
        required: true
        example: andy
      - name: password
        in: query
        description: This is your password.
        default: testPassword
        type: string
        validators:
          - PasswordValidator
        required: true
        example: 123456
    requestBody:
      contentType: x-www-form-urlencoded
      $ref: /xxx/xxx.json
    services:
      - SigninService
      - - ServiceInGather01
        - ServiceInGather02
      # Allows remote APIs to be called directly as services.
      - remoteServiceA
    events:
      onSuccesed:
        - onSuccesedEventName
      onError:
        - onErrorEventName
    responses:
      - code: 200
        description: You signin was sccussful!
        contentType: application/json
        $ref: /xxx/xxx.json
        example:
          - code: 200
          - message: You signin was sccussful!

# Send events can be automatically invoked at the end of a request by pre-declaring them.

events:
  - name: onSuccesedEventName
    description: xxxx
    services:
      - onSuccesedEventHandler1
      - - onSuccesedEventHandler2
        - onSuccesedEventHandler3

Well, the specification looks very simple and more intuitive, it can automatically register it have what APIs in web server and provide service by calling the service layer via pipeline or rendering a page. Also, it can automatically generate some resources to provide gRPC service or call some service from remote server. Additionally, you also can declare validators that can be validating parameters in request, using it automatically generates document of APIs etc.

​Now, we don't need controllers, we just need to write some yaml and it can automatically complete everything automatically if you want.

Summarizing the article that was my first English article, it probably not be so good. I'm trying to explain why we do not need controllers because the controller layer is not that important anymore. We split most responsibility of controller to service layer and validation layer or other layer with the development of Microservices for a long time.