Web application development framework-egg (3) 01-Basic functions – Directory stipulated by the directory structure agreement, the directory specified by the framework, the directory agreed by the built-in plug-in & the built-in objects of Application, context, Request & Response, etc.

Web application development framework-egg (3) 01-Basic functions – the directory structure agreed by the framework, the directory specified by the built-in plug-in & built-in objects Application, context, Request & Response, Controller ,Service,Helper,config

Basic functions

Conventions of directory structure

Egg’s principle: Agreement is greater than configuration

egg-project
├── package.json
├── app.js (optional)
├── agent.js (optional) // More unique
├── app
| ├── router.js
│ ├── controller
│ | └── home.js
│ ├── service (optional)
│ | └── user.js
│ ├── middleware (optional)
│ | └── response_time.js
│ ├── schedule (optional)
│ | └── my_task.js
│ ├── public (optional)
│ | └── reset.css
│ ├── view (optional)
│ | └── home.tpl
│ └── extend (optional)
│ ├── helper.js (optional)
│ ├── request.js (optional)
│ ├── response.js (optional)
│ ├── context.js (optional)
│ ├── application.js (optional)
│ └── agent.js (optional)
├── config
| ├── plugin.js
| ├── config.default.js
│ ├── config.prod.js
| ├── config.test.js (optional)
| ├── config.local.js (optional)
| └── config.unittest.js (optional)
└── test
    ├── middleware
    | └── response_time.test.js
    └── controller
        └── home.test.js

Directory specified by the framework
  • app/router.js is used to configure URL routing rules.
  • app/controller/** is used to parse user input and return corresponding results after processing.
  • app/service/** is used to write the business logic layer, optional.
  • app/middleware/** is used to write middleware, optional.
  • app/public/** is used to place static resources, optional.
  • app/extend/** is used for extensions to the framework, optional.
  • config/config.{env}.js is used to write configuration files.
  • config/plugin.js is used to configure the plug-ins that need to be loaded.
  • test/** is used for unit testing.
  • app.js and agent.js are used to customize the initialization work at startup, optional.
Directory agreed upon by built-in plug-ins
  • app/public/** is used to place static resources, optional.
  • app/schedule/** is used for scheduled tasks, optional.
Built-in objects

In this chapter, we will briefly introduce some of the basic objects built into the framework, including the four objects inherited from Koa (Application, Context, Request, Response) and some objects extended by the framework (Controller, Service, Helper, Config, Logger), we will encounter them frequently in subsequent courses.

Application

Application is a global application object. In an application, only one will be instantiated. It inherits from Koa.Application, on which we can mount some global methods and objects. We can easily extend the Application object in a plug-in or application.

Event

When the framework is running, some events will be triggered on the Application instance. Application developers or plug-in developers can listen to these events and perform some operations. As application developers, we usually monitor when launching custom scripts.

  • server: This event will only be triggered once per worker process. After the HTTP service is started, the HTTP server will be exposed to developers through this event.
  • error: When any exception occurs during runtime and is caught by the onerror plug-in, the error event will be triggered, exposing the error object and associated context (if any) to the developer. You can Carry out customized log record reporting and other processing.
  • request and response: When the application receives a request and responds to a request, the request and response events will be triggered respectively, and Exposing the current request context, developers can listen to these two events for logging.
// app.js

module.exports = app => {<!-- -->
  app.once('server', server => {<!-- -->
    // websocket
  });
  app.on('error', (err, ctx) => {<!-- -->
    // report error
  });
  app.on('request', ctx => {<!-- -->
    // log receive request
  });
  app.on('response', ctx => {<!-- -->
    // ctx.starttime is set by framework
    const used = Date.now() - ctx.starttime;
    // log total cost
  });
};

How to obtain

// app.js
module.exports = app => {<!-- -->
  app.xxxx = 'xxxx';
};

controller file

class UserController extends Controller {<!-- -->
  async fetch() {<!-- -->
    this.ctx.body = this.app.xxxx;
  }
}

Like Koa, on the Context object, the Application object can also be accessed through ctx.app.

context

Context is a request-level object, inherited from Koa.Context. Each time a user request is received, the framework will instantiate a Context object, which encapsulates the information of the user request and provides many convenient methods to obtain request parameters or set response information. The framework will mount all Services on the Context instance, and some plug-ins will also mount some other methods and objects on it (egg-sequelize will mount all models on the Context).

How to obtain

The most common ways to obtain Context instances are in Middleware, Controller and Service. The acquisition method in the Controller has been demonstrated in the above example. The acquisition method in the Service is the same as the acquisition method in the Controller. Obtaining the Context instance in the Middleware is the same as the way the Koa framework obtains the Context object in the middleware.

In addition to obtaining the Context instance when requesting, in some non-user request scenarios we need to access objects on the Context instance such as service / model. We can create one through the Application.createAnonymousContext() method Anonymous Context instance:

// app.js
module.exports = app => {<!-- -->
  app.beforeStart(async () => {<!-- -->
    const ctx = app.createAnonymousContext();
    // preload before app start
    await ctx.service.posts.load();
  });
}

Each task in the scheduled task accepts a Context instance as a parameter so that we can more conveniently execute some scheduled business logic:

// app/schedule/refresh.js
exports.task = async ctx => {<!-- -->
  await ctx.service.posts.refresh();
};
Request & amp; Response

Request is a request-level object, inherited from Koa.Request. It encapsulates the Node.js native HTTP Request object and provides a series of auxiliary methods to obtain common parameters of HTTP requests.

Response is a request-level object, inherited from Koa.Response. Encapsulates the Node.js native HTTP Response object and provides a series of auxiliary methods to set HTTP responses.

// app/controller/user.js
class UserController extends Controller {<!-- -->
  async fetch() {<!-- -->
    const {<!-- --> app, ctx } = this;
    const id = ctx.request.query.id;
    ctx.response.body = app.cache.get(id);
  }
}
Controller

The framework provides a Controller base class and recommends that all Controllers inherit from this base class implementation. The Controller base class has the following properties:

  • ctx – The Context instance of the current request.
  • app – The Application instance of the application.
  • config – Application configuration.
  • service – applies to all services.
  • logger – The logger object encapsulated for the current controller.

In a Controller file, you can reference the Controller base class in two ways:

// app/controller/user.js

// Get it from egg (recommended)
const Controller = require('egg').Controller;
class UserController extends Controller {<!-- -->
  //implement
}
module.exports = UserController;

// Get from app instance
module.exports = app => {<!-- -->
  return class UserController extends app.Controller {<!-- -->
    //implement
  };
};
Service

The framework provides a Service base class and recommends that all Services inherit from this base class implementation.

The properties of the Service base class are the same as those of the Controller base class, and the access methods are similar:

// app/service/user.js

// Get it from egg (recommended)
const Service = require('egg').Service;
class UserService extends Service {<!-- -->
  //implement
}
module.exports = UserService;

// Get from app instance
module.exports = app => {<!-- -->
  return class UserService extends app.Service {<!-- -->
    //implement
  };
};
Helper

Helper is used to provide some practical utility functions. Its function is that we can extract some commonly used actions into an independent function in helper.js, so that complex logic can be written in JavaScript to avoid the logic being scattered everywhere, and at the same time, test cases can be written better.

Helper itself is a class with the same properties as the Controller base class. It will also be instantiated on each request, so all functions on Helper can also obtain context information related to the current request.

How to obtain

The currently requested Helper(ctx.helper) instance can be obtained on the Context instance.

// app/controller/user.js
class UserController extends Controller {<!-- -->
  async fetch() {<!-- -->
    const {<!-- --> app, ctx } = this;
    const id = ctx.query.id;
    const user = app.cache.get(id);
    ctx.body = ctx.helper.formatUser(user);
  }
}

In addition, Helper instances can also be obtained in templates.

config

We can get the config object from the Application instance through app.config, or we can get the config object from the Controller, Service, Helper instance through this.config.