Skip to content
epiijsPublic

About

A simple server framework.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Repository files navigation

@epiijs/server

English

一个简单的 server 框架。

  • 显式 declare() 定义模块发现
  • Koa-like 管线
  • 基于文件系统的路由(不推荐)
  • Service 依赖注入
  • 可插拔日志

v4.x 只支持 ES module。

安装

npm i --save @epiijs/server

用法

项目长这样

(root)
├─ src
│  ├─ handlers
│  │  ├─ users
│  │  │  └─ index.ts
│  │  └─ index.ts
│  └─ services
│     └─ userService
│        └─ index.ts
└─ start.ts

对应的路由结果

=> /users    (declare routes)
=> /         (filesystem fallback)

启动服务

startServer 接收加载解析的完整 IAppConfig。

import { getDirNameByImportMeta, importConfig } from '@epiijs/config';
import { startServer } from '@epiijs/server';

const config = await importConfig({
  appRoot: getDirNameByImportMeta(import.meta)
});
startServer(config);

用 handler 处理请求

约定在 /handlers 目录下提供请求处理器。推荐用 declare 显式注册路由:

import {
  HandlerDeclareResult,
  HandlerResult,
  IncomingMessageWithParams,
  IServiceLocator
} from '@epiijs/server';

export function declare(): HandlerDeclareResult {
  return {
    routes: [
      { method: 'GET', path: '/users' },
      { method: 'GET', path: '/users/:id' }
    ]
  };
}

export default async function (
  this: IServiceLocator,
  message: IncomingMessageWithParams
): Promise<HandlerResult> {
  const { method, params } = message;

  // 简单响应
  return 'hello world';

  // 自定义响应
  return {
    status: 400,
    headers: { 'content-type': 'application/json' },
    content: JSON.stringify({})
  };
}

用 Handler 链组装管线

在 declare() 里用 handlers 组合 Handler 链(Koa-like 洋葱模型):

import {
  HandlerDeclareResult,
  HandlerFn,
  HandlerResult,
  IncomingMessageWithParams,
  IServiceLocator
} from '@epiijs/server';

async function withTiming(
  this: IServiceLocator,
  message: IncomingMessageWithParams,
  next: () => Promise<HandlerResult>
): Promise<HandlerResult> {
  const start = Date.now();
  const result = await next();
  console.log('elapsed', Date.now() - start);
  return result;
}

export function declare(): HandlerDeclareResult {
  return {
    routes: [{ method: 'GET', path: '/hello' }],
    handlers: [withTiming]
  };
}

export default async function (
  this: IServiceLocator,
  message: IncomingMessageWithParams
): Promise<HandlerResult> {
  return 'hello world';
}

注入 service 作为依赖

在 /services 下提供 service 工厂。

export interface IUserService {
  findUsers: () => Promise<IUser[]>;
}

export default function (services: IServiceLocator): IUserService {
  return {
    findUsers: async () => []
  };
}

Handler 内通过 this(绑定为 IServiceLocator)取用 service:

import {
  HandlerResult,
  IncomingMessageWithParams,
  IServiceLocator
} from '@epiijs/server';

export default async function (
  this: IServiceLocator,
  message: IncomingMessageWithParams
): Promise<HandlerResult> {
  const userService = this.userService as IUserService;
  const users = await userService.findUsers();
  return users;
}

自定义日志器

import { setTransport } from '@epiijs/server';

setTransport((method, ...args) => {
  // method = 'info' | 'error' | 'warn' | 'debug' | 'log' | ...
  // 转写给业务自己的日志器
});

Handler 内通过 this.appLogger 取用日志器:

export default async function (
  this: IServiceLocator,
  message: IncomingMessageWithParams
): Promise<HandlerResult> {
  this.appLogger.info('processing request', message.url);
  return 'ok';
}

从 V3 迁移

目录

actions/   →  handlers/

Handler 签名

// V3
export default async function (props: IncomingMessage, context: Context): Promise<ActionResult> {
  const userService = await context.useService('UserService');
  const config = context.getAppConfig();
  // ...
}

// V4
export default async function (
  this: IServiceLocator,
  message: IncomingMessageWithParams
): Promise<HandlerResult> {
  const userService = this.userService as IUserService;
  const config = this.appConfig as IAppConfig;
  // ...
}

管线(useHandler → handlers)

// V3
await context.useHandler(dispose => {
  const start = Date.now();
  if (message.method !== 'GET') {
    return { status: 405, content: 'method not allowed' };
  }
  dispose(() => console.log('elapsed', Date.now() - start));
});

// V4:声明 handlers
async function withTiming(this: IServiceLocator, message: IncomingMessageWithParams, next: () => Promise<HandlerResult>) {
  const start = Date.now();
  const result = await next();
  console.log('elapsed', Date.now() - start);
  return result;
}

export function declare() {
  return {
    routes: [{ method: 'GET', path: '/hello' }],
    handlers: [withTiming]
  };
}

类型改名

V3 V4
ActionResult HandlerResult
ActionFn HandlerFn
ActionDeclareResult HandlerDeclareResult
Context 移除

About

A simple server framework.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Used by

Contributors

Languages