dart_node_express

类型安全的 Express.js 绑定。完全使用 Dart 构建 HTTP 服务器和 REST API。

安装

dependencies:
  dart_node_express: ^0.11.0-beta

通过 npm 安装 Express:

npm install express

快速开始

import 'dart:js_interop';
import 'package:dart_node_express/dart_node_express.dart';

void main() {
  final app = express();

  app.get('/', handler((req, res) {
    res.send('Hello, Dart!');
  }));

  app.listen(3000, () {
    print('Server running on port 3000');
  }.toJS);
}

路由

基本路由

app.get('/users', handler((req, res) {
  res.jsonMap({'users': []});
}));

app.post('/users', handler((req, res) {
  final body = req.body;
  res.status(201);
  res.jsonMap({'created': true});
}));

app.put('/users/:id', handler((req, res) {
  final id = req.params['id'];
  res.jsonMap({'updated': id});
}));

app.delete('/users/:id', handler((req, res) {
  res.status(204);
  res.end();
}));

路由参数

app.get('/users/:userId/posts/:postId', handler((req, res) {
  final userId = req.params['userId'];
  final postId = req.params['postId'];

  res.jsonMap({
    'userId': userId,
    'postId': postId,
  });
}));

查询参数

app.get('/search', handler((req, res) {
  final query = req.query['q'];
  final page = int.tryParse(req.query['page'] ?? '1') ?? 1;

  res.jsonMap({
    'query': query,
    'page': page,
  });
}));

请求对象

Request 对象提供对传入请求数据的访问:

app.post('/api/data', handler((req, res) {
  // 请求体(需要 body-parsing 中间件)
  final body = req.body;

  // 请求头
  final contentType = req.headers['content-type'];

  // URL 路径
  final path = req.path;

  // HTTP 方法
  final method = req.method;

  // 查询字符串参数
  final params = req.query;

  res.jsonMap({'received': body});
}));

响应对象

Response 对象提供发送响应的方法:

// 发送文本
res.send('Hello!');

// 发送 JSON(对于 Dart Map,使用 jsonMap)
res.jsonMap({'message': 'Hello!'});

// 设置状态码(与响应分开调用)
res.status(201);
res.jsonMap({'created': true});

// 设置响应头
res.set('X-Custom-Header', 'value');

// 重定向
res.redirect('/new-location');

// 结束响应(无响应体)
res.status(204);
res.end();

中间件

自定义中间件

app.use(middleware((req, res, next) {
  print('${req.method} ${req.path}');
  next();
}));

链式中间件

app.use(chain([
  middleware((req, res, next) {
    print('First middleware');
    next();
  }),
  middleware((req, res, next) {
    print('Second middleware');
    next();
  }),
]));

请求上下文

在请求上下文中存储和检索值:

// 在中间件中设置上下文
app.use(middleware((req, res, next) {
  setContext(req, 'userId', '123');
  next();
}));

// 在处理程序中获取上下文
app.get('/profile', handler((req, res) {
  final userId = getContext<String>(req, 'userId');
  res.jsonMap({'userId': userId});
}));

路由器

使用路由器组织路由:

Router createUserRouter() {
  final router = Router();

  router.get('/', handler((req, res) {
    res.jsonMap({'users': []});
  }));

  router.post('/', handler((req, res) {
    res.status(201);
    res.jsonMap({'created': true});
  }));

  router.get('/:id', handler((req, res) {
    res.jsonMap({'user': req.params['id']});
  }));

  return router;
}

void main() {
  final app = express();

  // 挂载路由器
  final router = createUserRouter();
  app.use('/api/users', router);

  app.listen(3000);
}

异步处理程序

使用异步处理程序进行数据库调用和其他异步操作:

app.get('/users', asyncHandler((req, res) async {
  final users = await database.fetchUsers();
  res.jsonMap({'users': users});
}));

asyncHandler 包装器确保错误被正确捕获并传递给错误中间件。

验证

使用基于 Schema 的验证系统:

// 定义验证数据类型
typedef CreateUserData = ({String name, String email, int? age});

// 创建 Schema
final createUserSchema = schema<CreateUserData>(
  {
    'name': string().minLength(2).maxLength(50),
    'email': string().email(),
    'age': optional(int_().positive()),
  },
  (data) => (
    name: data['name'] as String,
    email: data['email'] as String,
    age: data['age'] as int?,
  ),
);

// 使用验证中间件
app.post('/users', validateBody(createUserSchema));
app.post('/users', handler((req, res) {
  final result = getValidatedBody<CreateUserData>(req);
  switch (result) {
    case Success(:final value):
      res.status(201);
      res.jsonMap({'name': value.name, 'email': value.email});
    case Error(:final error):
      res.status(400);
      res.jsonMap({'error': error});
  }
}));

可用验证器

// 字符串验证器
string().minLength(2).maxLength(100).notEmpty().email().alphanumeric()

// 整数验证器
int_().min(0).max(100).positive().range(1, 10)

// 布尔验证器
bool_()

// 可选包装器
optional(string())

完整示例

import 'dart:js_interop';
import 'package:dart_node_express/dart_node_express.dart';

void main() {
  final app = express();

  // 日志中间件
  app.use(middleware((req, res, next) {
    print('[${DateTime.now()}] ${req.method} ${req.path}');
    next();
  }));

  // 路由
  app.get('/', handler((req, res) {
    res.jsonMap({
      'name': 'My API',
      'version': '1.0.0',
    });
  }));

  app.get('/health', handler((req, res) {
    res.jsonMap({'status': 'ok'});
  }));

  // 挂载路由器
  app.use('/api/users', createUserRouter());

  // 启动服务器
  app.listen(3000, () {
    print('Server running on port 3000');
  }.toJS);
}

源代码

源代码可在 GitHub 上获取。