Dart Frog 教程 第2部分:构建你的第一个真实 REST API(完整 CRUD 与 Todos) 🐸
发布: (2026年1月14日 GMT+8 05:07)
3 分钟阅读
原文: Dev.to
Source: Dev.to
规划与最佳实践
Quick plan – 我们将创建一个包含 id、title 和 completed 状态的 Todo 模型,存储在内存中(使用 Map 进行快速查找)。这使示例保持简洁,同时以后可以轻松替换为真实数据库。
Best practices
- 使用
[id].dart的动态路由 - 使用 uuid 包生成唯一 ID
- 验证 JSON 请求体
- 返回适当的 HTTP 状态码:
200、201、204、400、404、405
设置
添加 UUID 依赖
# pubspec.yaml
dependencies:
uuid: ^4.5.0
运行包管理器:
dart pub get # or flutter pub get
Todo 模型
Create lib/src/todo.dart:
/// Represents a Todo item.
class Todo {
/// Creates a new Todo.
Todo({
required this.id,
required this.title,
this.isCompleted = false,
});
/// Creates a Todo from a JSON map.
factory Todo.fromJson(Map json) => Todo(
id: json['id'] as String,
title: json['title'] as String,
isCompleted: json['isCompleted'] as bool? ?? false,
);
/// Unique identifier.
final String id;
/// Title of the todo.
final String title;
/// Completion status.
bool isCompleted;
/// Converts the Todo to JSON.
Map toJson() => {
'id': id,
'title': title,
'isCompleted': isCompleted,
};
}
内存存储
import 'package:my_project/src/todo.dart';
import 'package:uuid/uuid.dart';
const _uuid = Uuid();
final _todos = {};
/// Returns all todos.
List getAllTodos() => _todos.values.toList();
/// Returns a todo by its [id] or `null` if not found.
Todo? getTodoById(String id) => _todos[id];
/// Creates a new todo with the given [title].
void createTodo(String title) {
final id = _uuid.v4();
_todos[id] = Todo(id: id, title: title);
}
/// Updates an existing todo.
void updateTodo(String id, {String? title, bool? isCompleted}) {
final todo = _todos[id];
if (todo == null) return;
_todos[id] = Todo(
id: id,
title: title ?? todo.title,
isCompleted: isCompleted ?? todo.isCompleted,
);
}
/// Deletes a todo.
void deleteTodo(String id) => _todos.remove(id);
路由
集合路由 – routes/todos/index.dart
import 'package:dart_frog/dart_frog.dart';
import 'package:my_project/src/todo_repository.dart';
Future onRequest(RequestContext context) async {
switch (context.request.method) {
case HttpMethod.get:
final todos = getAllTodos();
return Response.json(
body: todos.map((e) => e.toJson()).toList(),
);
case HttpMethod.post:
final body = await context.request.json() as Map;
final title = body['title'] as String?;
if (title == null || title.isEmpty) {
return Response(statusCode: 400, body: 'Title is required');
}
createTodo(title);
return Response(statusCode: 201, body: 'Todo created');
default:
return Response(statusCode: 405);
}
}
动态项目路由 – routes/todos/[id].dart
import 'package:dart_frog/dart_frog.dart';
import 'package:my_project/src/todo_repository.dart';
Future onRequest(RequestContext context, String id) async {
final todo = getTodoById(id);
if (todo == null) return Response(statusCode: 404);
switch (context.request.method) {
case HttpMethod.get:
return Response.json(body: todo.toJson());
case HttpMethod.put:
final body = await context.request.json() as Map;
final title = body['title'] as String?;
final isCompleted = body['isCompleted'] as bool?;
updateTodo(id, title: title, isCompleted: isCompleted);
return Response.json(body: getTodoById(id)!.toJson());
case HttpMethod.delete:
deleteTodo(id);
return Response(statusCode: 204);
default:
return Response(statusCode: 405);
}
}
测试
快速 curl 示例:
# Get all todos
curl http://localhost:8080/todos
# Create a new todo
curl -X POST http://localhost:8080/todos \
-H "Content-Type: application/json" \
-d '{"title": "Learn Dart Frog"}'
# Get a specific todo (replace <id> with the actual id)
curl http://localhost:8080/todos/<id>
API 能够优雅地处理错误,并提供坚实的生产就绪基础。
源代码
通过给仓库加星并关注作者来表达一点 ❤️:
https://github.com/techwithsam/dart_frog_full_course_tutorial
这是你的第一个真正的 Dart Frog REST API —— 恭喜!接下来:将 Flutter 应用连接到它。