极简接口定义和响应定义,支持更多的解析器

This commit is contained in:
Cody
2026-03-09 11:04:52 +08:00
parent a063ce178e
commit 03b89706a5
14 changed files with 482 additions and 261 deletions

View File

@@ -886,8 +886,9 @@ flowchart TD
│ ├── annotations/
│ │ └── api_request.dart # @ApiRequest 注解定义
│ ├── generator/
│ │ ├── api_request_generator.dart # build_runner 代码生成器实现
│ │ ── builder.dart # SharedPartBuilder 入口
│ │ ├── api_request_generator.dart # Request mixin 生成器toJson / path / method / fromJson 注册)
│ │ ── api_response_generator.dart # Response fromJson 生成器(从 @ApiRequest(responseType) 自动推导,递归嵌套类型)
│ │ └── builder.dart # SharedPartBuilder 入口(两个生成器合并到同一 .g.dart
│ ├── data/
│ │ ├── datasources/
│ │ │ ├── http/
@@ -2286,23 +2287,21 @@ extension APIRequestableExtension<T> on APIRequestable<T> {
<p>一个端点 = 一个文件(<code>data/remote/login_request.dart</code>Response DTO + Request 放在同一文件中。</p>
<pre><code class="language-dart">import 'package:json_annotation/json_annotation.dart';
import 'package:networks_sdk/networks_sdk.dart';
<pre><code class="language-dart">import 'package:networks_sdk/networks_sdk.dart';
part 'login_request.g.dart';
// ── Response DTO ──
// ── Response DTO(纯 Dart 类,零注解,零样板)──
// _$LoginResponseFromJson 由 ApiResponseGenerator 从 @ApiRequest(responseType: T) 自动推导生成
@JsonSerializable()
class LoginData {
class LoginResponse {
final String token;
@JsonKey(name: 'user_id')
@JsonKey(name: 'user_id') // @JsonKey 由生成器读取Response 类不需要 @JsonSerializable
final String userId;
final String email;
const LoginData({required this.token, required this.userId, required this.email});
factory LoginData.fromJson(Map&lt;String, dynamic&gt; json) =&gt; _$LoginDataFromJson(json);
Map&lt;String, dynamic&gt; toJson() =&gt; _$LoginDataToJson(this);
const LoginResponse({required this.token, required this.userId, required this.email});
// 无 factory fromJson — 生成器在 .g.dart 中提供私有 _$LoginResponseFromJson
User toEntity() =&gt; User(id: userId, email: email); // DTO → Domain Entity
}
@@ -2313,23 +2312,23 @@ class LoginData {
@ApiRequest(
path: ApiPaths.authLogin, // 路径统一在 core/foundation/api_paths.dart 管理
method: HttpMethod.post,
responseType: LoginData,
responseType: LoginResponse,
requestType: ApiRequestType.login,
)
class LoginRequest extends ApiRequestable&lt;LoginData&gt; with _$LoginRequestApi {
class LoginRequest extends ApiRequestable&lt;LoginResponse&gt; with _$LoginRequestApi {
final String email;
final String password;
LoginRequest({required this.email, required this.password});
// 完毕toJson 由 mixin 从类字段自动生成fromJson 不需要Request 永远手动构造)
// 完毕toJson 由 mixin 从类字段自动生成fromJson 注册也全部自动处理
}
</code></pre>
<pre><code class="language-dart">// 使用 - 超级简单!
final loginData = await apiClient.executeRequest(
final loginResponse = await apiClient.executeRequest(
LoginRequest(email: 'user@example.com', password: '123456'),
);
final user = loginData?.toEntity(); // DTO → Domain Entity
final user = loginResponse?.toEntity(); // DTO → Domain Entity
</code></pre>
<div style="background: #e8f5e9; padding: 20px; border-radius: 8px; border-left: 4px solid #388e3c; margin: 20px 0;">
@@ -2359,8 +2358,8 @@ final user = loginData?.toEntity(); // DTO → Domain Entity
</tr>
<tr>
<td><strong>@ApiRequest当前方案</strong></td>
<td>字段 + 构造函数 + @ApiRequest</td>
<td>path / method / requestType / includeToken / toJson / fromJson 注册</td>
<td>字段 + 构造函数 + @ApiRequest<br/><em>Response DTO字段 + 构造函数,零注解)</em></td>
<td>Request: path / method / requestType / includeToken / toJson / fromJson 注册<br/>Response: _$XFromJson 私有反序列化函数(按需递归生成嵌套类型)</td>
<td><strong>极低</strong></td>
</tr>
</tbody>
@@ -2368,10 +2367,10 @@ final user = loginData?.toEntity(); // DTO → Domain Entity
<p><strong>核心优势</strong></p>
<ul>
<li><strong>注解驱动</strong><code>@ApiRequest</code> 一个注解自动生成 mixin含 toJson无需 <code>@JsonSerializable</code></li>
<li><strong>Request 零样板</strong><code>@ApiRequest</code> 一个注解生成 mixin含 toJson无需 <code>@JsonSerializable</code></li>
<li><strong>Response 零注解</strong>Response DTO 不需要 <code>@JsonSerializable</code>,不需要 <code>factory fromJson</code><code>_$XFromJson</code> 由生成器从 <code>@ApiRequest(responseType: T)</code> 自动推导;嵌套自定义类型递归生成,依赖关系自动处理</li>
<li><strong>自动注册</strong>fromJson 在首次请求时自动注册到全局注册表,无需手动 <code>registerApiResponses()</code></li>
<li><strong>一个端点 = 一个文件</strong>Response DTO + Request 放在同一文件,打开即看全貌</li>
<li><strong>傻瓜式使用</strong>:使用者只需关注业务字段和注解配置</li>
<li><strong>类型安全</strong><code>ApiRequestable&lt;T&gt;</code> 泛型 + <code>responseType</code> 编译期检查</li>
</ul>
@@ -2387,12 +2386,12 @@ final user = loginData?.toEntity(); // DTO → Domain Entity
<tbody>
<tr>
<td><strong>Swift</strong></td>
<td><code>struct LoginRequest: APIRequestable { typealias Response = LoginData ... }</code></td>
<td><code>struct LoginRequest: APIRequestable { typealias Response = LoginResponse ... }</code></td>
<td>协议直接实现,最简洁</td>
</tr>
<tr>
<td><strong>Dart</strong></td>
<td><code>@ApiRequest(...) class LoginRequest extends ApiRequestable&lt;LoginData&gt; with _$LoginRequestApi { ... }</code></td>
<td><code>@ApiRequest(...) class LoginRequest extends ApiRequestable&lt;LoginResponse&gt; with _$LoginRequestApi { ... }</code></td>
<td>注解 + 代码生成,接近 Swift 体验</td>
</tr>
</tbody>
@@ -2530,26 +2529,23 @@ melos run gen
<h6>4.5 更多使用示例</h6>
<p>所有示例遵循同一模式:<code>@ApiRequest</code> + <code>extends ApiRequestable&lt;T&gt; with _$XxxApi</code>。Request 无需 <code>@JsonSerializable</code></p>
<p>所有示例遵循同一模式:<code>@ApiRequest</code> + <code>extends ApiRequestable&lt;T&gt; with _$XxxApi</code>。Request 和 Response 均无需 <code>@JsonSerializable</code>Response DTO 连 <code>factory fromJson</code> 也不需要</p>
<p><strong>发送消息请求POST + @JsonKey 字段重命名):</strong></p>
<pre><code class="language-dart">// data/remote/send_message_request.dart
// ── Response DTO仍用 @JsonSerializable)──
@JsonSerializable()
class SendMessageData {
// ── Response DTO纯 Dart 类零注解_$SendMessageResponseFromJson 由生成器自动提供)──
class SendMessageResponse {
@JsonKey(name: 'message_id')
final String messageId;
final int timestamp;
const SendMessageData({required this.messageId, required this.timestamp});
factory SendMessageData.fromJson(Map&lt;String, dynamic&gt; json) =&gt;
_$SendMessageDataFromJson(json);
const SendMessageResponse({required this.messageId, required this.timestamp});
}
// ── Request零样板──
@ApiRequest(path: ApiPaths.chatSendMessage, responseType: SendMessageData)
class SendMessageRequest extends ApiRequestable&lt;SendMessageData&gt;
@ApiRequest(path: ApiPaths.chatSendMessage, responseType: SendMessageResponse)
class SendMessageRequest extends ApiRequestable&lt;SendMessageResponse&gt;
with _$SendMessageRequestApi {
@JsonKey(name: 'chat_id') // 生成器会读取JSON 键名为 'chat_id'
final String chatId;
@@ -2563,23 +2559,21 @@ class SendMessageRequest extends ApiRequestable&lt;SendMessageData&gt;
<p><strong>获取用户资料GET靠 token 标识当前用户,无需传参):</strong></p>
<pre><code class="language-dart">// data/remote/get_profile_request.dart
@JsonSerializable(createToJson: false) // 只需反序列化
class ProfileData {
// ── Response DTO纯 Dart 类零注解_$ProfileResponseFromJson 由生成器自动提供)──
class ProfileResponse {
@JsonKey(name: 'user_id')
final String userId;
final String email;
final String? nickname;
final String? avatar;
const ProfileData({required this.userId, required this.email, this.nickname, this.avatar});
factory ProfileData.fromJson(Map&lt;String, dynamic&gt; json) =&gt;
_$ProfileDataFromJson(json);
const ProfileResponse({required this.userId, required this.email, this.nickname, this.avatar});
User toEntity() =&gt; User(id: userId, email: email, nickname: nickname, avatar: avatar);
}
@ApiRequest(path: ApiPaths.userProfile, method: HttpMethod.get, responseType: ProfileData)
class GetProfileRequest extends ApiRequestable&lt;ProfileData&gt;
@ApiRequest(path: ApiPaths.userProfile, method: HttpMethod.get, responseType: ProfileResponse)
class GetProfileRequest extends ApiRequestable&lt;ProfileResponse&gt;
with _$GetProfileRequestApi {
GetProfileRequest(); // 无参数 — toJson 自动生成空 map
}
@@ -2588,14 +2582,12 @@ class GetProfileRequest extends ApiRequestable&lt;ProfileData&gt;
<p><strong>上传文件请求FormData multipart</strong></p>
<pre><code class="language-dart">// data/remote/upload_file_request.dart
@JsonSerializable()
// ── Response DTO纯 Dart 类零注解_$UploadResultFromJson 由生成器自动提供)──
class UploadResult {
final String url;
@JsonKey(name: 'file_id')
final String fileId;
const UploadResult({required this.url, required this.fileId});
factory UploadResult.fromJson(Map&lt;String, dynamic&gt; json) =&gt;
_$UploadResultFromJson(json);
}
@ApiRequest(
@@ -2624,7 +2616,8 @@ class UploadFileRequest extends ApiRequestable&lt;UploadResult&gt;
<div style="background: #fff3cd; padding: 15px; border-radius: 8px; border-left: 4px solid #ffc107; margin: 20px 0;">
<p><strong>核心价值</strong></p>
<ul style="margin-bottom: 0;">
<li><strong>极简使用</strong>:字段 + 构造函数 + <code>@ApiRequest</code>Request 无需 <code>@JsonSerializable</code>、无需 <code>fromJson</code>、无需手写 <code>toJson</code></li>
<li><strong>Request 极简</strong>:字段 + 构造函数 + <code>@ApiRequest</code>(无需 <code>@JsonSerializable</code>、无需手写 <code>toJson</code></li>
<li><strong>Response 零注解</strong>Response DTO 是纯 Dart 类,无需 <code>@JsonSerializable</code>,无需 <code>factory fromJson</code><code>_$XFromJson</code> 由生成器从 <code>responseType</code> 自动推导</li>
<li><strong>零维护</strong>path / method / requestType / includeToken / toJson / fromJson 注册 全部自动生成</li>
<li><strong>类型安全</strong>:泛型 <code>ApiRequestable&lt;T&gt;</code> + <code>responseType</code> 编译期检查</li>
<li><strong>一个端点 = 一个文件</strong>Response DTO + Request 放在同一文件,打开即看全貌</li>
@@ -2721,11 +2714,11 @@ class LoginViewModel extends _$LoginViewModel {
→ LoggingInterceptor ← 请求/响应日志
← request.decodeResponse(response) ← 自动解码
← ApiResponseWrapper.fromJson ← 拆 { code, msg, data }
← fromJsonRegistry[LoginData] ← 查注册表
← LoginData.fromJson(data) ← 反序列化
← LoginDataDTO
← fromJsonRegistry[LoginResponse] ← 查注册表
_$LoginResponseFromJson(data) ← 反序列化(生成的私有函数)
← LoginResponseDTO
→ onTokenUpdate(token) ← 回调写入 Token内存 + 持久化)
← loginData.toEntity() → User ← DTO → Domain Entity
← loginResponse.toEntity() → User ← DTO → Domain Entity
← User
← state.copyWith(user: user) ← 更新状态
View: ref.watch → 自动 rebuild ← UI 刷新
@@ -5715,7 +5708,7 @@ class MessageLocalDataSource {
class MessageRepositoryImpl implements MessageRepository {
final NetworksSdkApi _client;
Future&lt;SendMessageData?&gt; sendMessage({
Future&lt;SendMessageResponse?&gt; sendMessage({
required String chatId,
required String content,
}) {
@@ -5978,7 +5971,7 @@ flowchart LR
<tr><th>层级</th><th>文件命名</th><th>类命名</th><th>示例</th></tr>
</thead>
<tbody>
<tr><td>接口定义</td><td><code>{action}_request.dart</code></td><td>Request: <code>{Action}Request</code><br/>Response DTO: <code>{Action}Data</code></td><td><code>login_request.dart</code><code>LoginRequest</code> + <code>LoginData</code></td></tr>
<tr><td>接口定义</td><td><code>{action}_request.dart</code></td><td>Request: <code>{Action}Request</code><br/>Response DTO: <code>{Action}Response</code></td><td><code>login_request.dart</code><code>LoginRequest</code> + <code>LoginResponse</code></td></tr>
<tr><td>持久化 DTO</td><td><code>data/models/{entity}_dto.dart</code></td><td><code>{Entity}Dto</code></td><td><code>user_dto.dart</code><code>UserDto</code></td></tr>
<tr><td>Repository 接口</td><td><code>domain/repositories/{module}_repository.dart</code></td><td><code>{Module}Repository</code></td><td><code>auth_repository.dart</code><code>AuthRepository</code></td></tr>
<tr><td>Repository 实现</td><td><code>data/repositories/{module}_repository_impl.dart</code></td><td><code>{Module}RepositoryImpl</code></td><td><code>auth_repository_impl.dart</code><code>AuthRepositoryImpl</code></td></tr>
@@ -5990,8 +5983,8 @@ flowchart LR
<p><strong>关键规则</strong></p>
<ul>
<li><strong>一个端点 = 一个 Request 文件</strong>Response DTO + Request 类放在同一文件中</li>
<li><strong>Response DTO 必须有 <code>toEntity()</code></strong>:统一 DTO → Domain Entity 的转换入口</li>
<li><strong>持久化 DTO 和 Response DTO 分开</strong>Response DTO<code>XxxData</code>)在 request 文件中,持久化 DTO<code>XxxDto</code>)在 <code>data/models/</code></li>
<li><strong>Response DTO 是纯 Dart 类</strong>:零注解、零 <code>factory fromJson</code>;只需字段 + 构造函数,<code>toEntity()</code> 按需添加</li>
<li><strong>持久化 DTO 和 Response DTO 分开</strong>Response DTO<code>XxxResponse</code>)在 request 文件中,持久化 DTO<code>XxxDto</code>)在 <code>data/models/</code></li>
<li><strong>禁止跳层</strong>ViewModel → Repository→ UseCase 按需)→ NetworksSdkApi每层职责明确</li>
</ul>
@@ -6041,8 +6034,10 @@ part 'login_request.g.dart'; // 这行必须写!指向即将自动生成的
<pre><code class="language-dart">// ── Response DTO ──
/// 服务端返回的登录数据
@JsonSerializable() // ← 这个注解让 build_runner 自动生成 fromJson / toJson
class LoginData {
/// 纯 Dart 类,零注解,零样板。
/// _$LoginResponseFromJson 由 ApiResponseGenerator 从 @ApiRequest(responseType: LoginResponse) 自动推导生成,
/// 无需手动添加任何注解或 factory fromJson。
class LoginResponse {
final String token; // 服务端返回的字段
@JsonKey(name: 'user_id') // 服务端字段名是 user_idDart 字段名是 userId
final String userId;
@@ -6050,18 +6045,15 @@ class LoginData {
final String? nickname; // 可选字段用 String?
final String? avatar;
const LoginData({ // 构造函数,参数和字段一一对应
const LoginResponse({ // 构造函数,参数和字段一一对应
required this.token,
required this.userId,
required this.email,
this.nickname,
this.avatar,
});
// ↓ 这两行是固定写法,照抄就行,把类名替换掉
factory LoginData.fromJson(Map&lt;String, dynamic&gt; json) =&gt;
_$LoginDataFromJson(json); // ← 短暂报红watch 模式下保存后几秒自动消失
Map&lt;String, dynamic&gt; toJson() =&gt; _$LoginDataToJson(this);
// 不需要 factory fromJson不需要 toJson不需要任何注解
// 生成器自动在 login_request.g.dart 中生成 _$LoginResponseFromJson 私有函数
/// DTO → Domain Entity把网络层数据转为业务层数据
User toEntity() {
@@ -6103,19 +6095,16 @@ class LoginData {
@ApiRequest( // ← 这个注解让 build_runner 自动生成 path / method 等
path: ApiPaths.authLogin, // 路径常量,定义在 core/foundation/api_paths.dart
method: HttpMethod.post, // HTTP 方法,从接口文档抄
responseType: LoginData, // 响应类型,就是上面写的 LoginData
responseType: LoginResponse, // 响应类型,就是上面写的 LoginResponse
requestType: ApiRequestType.login, // login 类型不携带 Token登录前还没有 Token
)
@JsonSerializable() // ← 自动生成 toJson把请求参数序列化为 JSON
class LoginRequest extends ApiRequestable&lt;LoginData&gt; // ← 固定写法extends ApiRequestable&lt;响应类型&gt;
with _$LoginRequestApi { // ← 固定写法with _$类名Api短暂报红保存后自动消失
class LoginRequest extends ApiRequestable&lt;LoginResponse&gt; // ← 固定写法extends ApiRequestable&lt;响应类型&gt;
with _$LoginRequestApi { // ← 固定写法with _$类名Api短暂报红保存后自动消失
final String email; // 请求参数:要发给服务端的字段
final String password;
LoginRequest({required this.email, required this.password});
@override
Map&lt;String, dynamic&gt; toJson() =&gt; _$LoginRequestToJson(this); // ← 固定写法,短暂报红,保存后自动消失
// 完毕toJson 由 _$LoginRequestApi mixin 从类字段自动生成,不需要 @JsonSerializable不需要手写 toJson
}
</code></pre>
@@ -6124,14 +6113,14 @@ class LoginRequest extends ApiRequestable&lt;LoginData&gt; // ← 固定写法
<div style="background: #fff3cd; padding: 15px; border-radius: 8px; border-left: 4px solid #ffc107; margin: 15px 0;">
<p style="margin-top: 0; font-weight: 700; color: #f57f17;">命名规则速查(写之前就能确定引用名)</p>
<table>
<thead><tr><th>你写的类名</th><th>fromJson</th><th>toJson</th><th>Api mixin</th></tr></thead>
<thead><tr><th>你写的类名</th><th>fromJson(私有函数)</th><th>toJson</th><th>Api mixin</th><th>来源</th></tr></thead>
<tbody>
<tr><td><code>LoginData</code></td><td><code>_$LoginDataFromJson</code></td><td><code>_$LoginDataToJson</code></td><td>-</td></tr>
<tr><td><code>LoginRequest</code></td><td><code>_$LoginRequestFromJson</code></td><td><code>_$LoginRequestToJson</code></td><td><code>_$LoginRequestApi</code></td></tr>
<tr><td><code>SendMessageRequest</code></td><td><code>_$SendMessageRequestFromJson</code></td><td><code>_$SendMessageRequestToJson</code></td><td><code>_$SendMessageRequestApi</code></td></tr>
<tr><td><code>LoginResponse</code></td><td><code>_$LoginResponseFromJson</code></td><td>-(不需要)</td><td>-</td><td>ApiResponseGenerator 自动推导</td></tr>
<tr><td><code>LoginRequest</code></td><td>-(不需要)</td><td>由 mixin 自动生成</td><td><code>_$LoginRequestApi</code></td><td>ApiRequestGenerator 生成 mixin</td></tr>
<tr><td><code>SendMessageRequest</code></td><td>-(不需要)</td><td>由 mixin 自动生成</td><td><code>_$SendMessageRequestApi</code></td><td>ApiRequestGenerator 生成 mixin</td></tr>
</tbody>
</table>
<p style="margin-bottom: 0;">规则:<code>_$</code> + 类名 + <code>FromJson</code> / <code>ToJson</code> / <code>Api</code>。固定前缀,直接拼</p>
<p style="margin-bottom: 0;">规则:Response DTO 类名拼 <code>_$</code> + 类名 + <code>FromJson</code>(私有,只在 .g.dart 内部使用Request 类名拼 <code>_$</code> + 类名 + <code>Api</code>mixin</p>
</div>
<!-- ────────── 第 2 步 ────────── -->
@@ -6162,19 +6151,19 @@ class AuthRepositoryImpl implements AuthRepository {
required String password,
}) async {
// 1. 调 NetworksSdkApi构造请求 → 发 HTTP → 自动解码 → 返回 DTO
final LoginData? loginData = await _client.executeRequest(
final LoginResponse? loginResponse = await _client.executeRequest(
LoginRequest(email: email, password: password),
);
if (loginData == null) {
if (loginResponse == null) {
throw Exception('Login failed: empty response');
}
// 2. 回调写入 Token内存 + 持久化由 Provider 层组合)
_onTokenUpdate(loginData.token);
_onTokenUpdate(loginResponse.token);
// 3. DTO → Domain Entity返回给上层
return loginData.toEntity();
return loginResponse.toEntity();
}
}
</code></pre>
@@ -6321,10 +6310,10 @@ class LoginViewModel extends _$LoginViewModel {
→ AuthRepositoryImpl.login() // data/repositories/
→ _client.executeRequest(LoginRequest) // 调 NetworksSdkApi
→ Auth → Encryption → Dio.request → Retry → Logging // 拦截器链自动处理
← request.decodeResponse → LoginData.fromJson // 自动解码
← LoginDataDTO
← request.decodeResponse → _$LoginResponseFromJson // 自动解码(生成的私有函数)
← LoginResponseDTO
→ onTokenUpdate(token) // 回调:内存写入 + 持久化
← loginData.toEntity() → UserDomain Entity
← loginResponse.toEntity() → UserDomain Entity
← User
← state = state.copyWith(user: user) // 更新状态
← View: ref.watch → 自动 rebuild → UI 显示用户信息 // 自动刷新
@@ -6345,22 +6334,18 @@ class LoginViewModel extends _$LoginViewModel {
<p><strong>你只需创建一个文件</strong><code>lib/data/remote/send_message_request.dart</code>,然后在 Repository 中调用即可。</p>
<pre><code class="language-dart">import 'package:json_annotation/json_annotation.dart';
import 'package:networks_sdk/networks_sdk.dart';
<pre><code class="language-dart">import 'package:networks_sdk/networks_sdk.dart';
part 'send_message_request.g.dart';
// ── Response DTO ──
// ── Response DTO(纯 Dart 类零注解_$SendMessageResponseFromJson 由生成器自动提供)──
@JsonSerializable()
class SendMessageData {
class SendMessageResponse {
@JsonKey(name: 'message_id')
final String messageId;
final int timestamp;
const SendMessageData({required this.messageId, required this.timestamp});
factory SendMessageData.fromJson(Map&lt;String, dynamic&gt; json) =&gt;
_$SendMessageDataFromJson(json);
const SendMessageResponse({required this.messageId, required this.timestamp});
}
// ── Request ──
@@ -6368,26 +6353,24 @@ class SendMessageData {
@ApiRequest(
path: ApiPaths.chatSendMessage, // 路径常量,定义在 api_paths.dart
method: HttpMethod.post, // HTTP 方法
responseType: SendMessageData, // 响应类型
responseType: SendMessageResponse, // 响应类型
// requestType 不写,默认 ApiRequestType.request会携带 Token
)
@JsonSerializable()
class SendMessageRequest extends ApiRequestable&lt;SendMessageData&gt;
class SendMessageRequest extends ApiRequestable&lt;SendMessageResponse&gt;
with _$SendMessageRequestApi {
@JsonKey(name: 'chat_id') // JSON 字段名和 Dart 字段名不一样时用 @JsonKey
final String chatId;
final String content;
SendMessageRequest({required this.chatId, required this.content});
@override
Map&lt;String, dynamic&gt; toJson() =&gt; _$SendMessageRequestToJson(this);
// toJson 自动生成:{'chat_id': chatId, 'content': content}
}
</code></pre>
<p>保存 → 自动生成 → 然后在 Repository 中调 NetworksSdkApi 就完了:</p>
<pre><code class="language-dart">// 在 MessageRepositoryImpl 中添加
Future&lt;SendMessageData?&gt; sendMessage({
Future&lt;SendMessageResponse?&gt; sendMessage({
required String chatId,
required String content,
}) {
@@ -6407,22 +6390,19 @@ Future&lt;SendMessageData?&gt; sendMessage({
<pre><code class="language-dart">// lib/data/remote/get_profile_request.dart
import 'package:json_annotation/json_annotation.dart';
import 'package:networks_sdk/networks_sdk.dart';
part 'get_profile_request.g.dart';
@JsonSerializable()
class ProfileData {
// ── Response DTO纯 Dart 类零注解_$ProfileResponseFromJson 由生成器自动提供)──
class ProfileResponse {
@JsonKey(name: 'user_id')
final String userId;
final String email;
final String? nickname;
final String? avatar;
const ProfileData({required this.userId, required this.email, this.nickname, this.avatar});
factory ProfileData.fromJson(Map&lt;String, dynamic&gt; json) =&gt;
_$ProfileDataFromJson(json);
const ProfileResponse({required this.userId, required this.email, this.nickname, this.avatar});
User toEntity() =&gt; User(id: userId, email: email, nickname: nickname, avatar: avatar);
}
@@ -6430,15 +6410,12 @@ class ProfileData {
@ApiRequest(
path: ApiPaths.userProfile,
method: HttpMethod.get, // ← GET 请求toJson() 结果作为 query string
responseType: ProfileData,
responseType: ProfileResponse,
)
@JsonSerializable()
class GetProfileRequest extends ApiRequestable&lt;ProfileData&gt;
class GetProfileRequest extends ApiRequestable&lt;ProfileResponse&gt;
with _$GetProfileRequestApi {
GetProfileRequest(); // 无参数 — token 标识当前用户,无需显式传 user_id
@override
Map&lt;String, dynamic&gt; toJson() =&gt; _$GetProfileRequestToJson(this);
// toJson 自动生成空 map {}
}
</code></pre>
@@ -6685,41 +6662,33 @@ melos run gen:watch
<pre><code class="language-dart">// data/remote/login_request.dart
import 'package:json_annotation/json_annotation.dart';
import 'package:networks_sdk/networks_sdk.dart';
part 'login_request.g.dart'; // ← 必须写,指向即将生成的文件
// ── Response DTO ──
@JsonSerializable()
class LoginData {
// ── Response DTO(纯 Dart 类,零注解,零样板)──
// _$LoginResponseFromJson 由 ApiResponseGenerator 从 @ApiRequest(responseType: LoginResponse) 自动推导生成
class LoginResponse {
final String token;
final String email;
const LoginData({required this.token, required this.email});
// ↓ 此时 _$LoginDataFromJson 还不存在IDE 会报红,正常!
factory LoginData.fromJson(Map&lt;String, dynamic&gt; json) =&gt;
_$LoginDataFromJson(json);
Map&lt;String, dynamic&gt; toJson() =&gt; _$LoginDataToJson(this);
const LoginResponse({required this.token, required this.email});
// 不需要 factory fromJson不需要任何注解
}
// ── Request ──
@ApiRequest(
path: ApiPaths.authLogin,
method: HttpMethod.post,
responseType: LoginData,
responseType: LoginResponse,
requestType: ApiRequestType.login,
)
@JsonSerializable()
class LoginRequest extends ApiRequestable&lt;LoginData&gt;
class LoginRequest extends ApiRequestable&lt;LoginResponse&gt;
with _$LoginRequestApi { // ← 短暂报红,保存后自动消失
final String email;
final String password;
LoginRequest({required this.email, required this.password});
@override
Map&lt;String, dynamic&gt; toJson() =&gt; _$LoginRequestToJson(this); // ← 短暂报红,保存后自动消失
// toJson 由 mixin 自动生成,保存后红线自动消失
}
</code></pre>
@@ -6734,11 +6703,10 @@ class LoginRequest extends ApiRequestable&lt;LoginData&gt;
<p style="margin-top: 0; font-weight: 700; color: #c62828;">命名规则(写之前就能确定引用名)</p>
<table>
<thead><tr><th>注解</th><th>生成的符号</th><th>示例</th></tr></thead>
<thead><tr><th>来源</th><th>生成的符号</th><th>示例</th></tr></thead>
<tbody>
<tr><td><code>@JsonSerializable()</code></td><td><code>_$类名FromJson()</code></td><td><code>_$LoginDataFromJson(json)</code></td></tr>
<tr><td><code>@JsonSerializable()</code></td><td><code>_$类名ToJson()</code></td><td><code>_$LoginDataToJson(this)</code></td></tr>
<tr><td><code>@ApiRequest(...)</code></td><td><code>_$类名Api</code>mixin</td><td><code>_$LoginRequestApi</code></td></tr>
<tr><td><code>@ApiRequest(responseType: T)</code><br/>ApiResponseGenerator 推导)</td><td><code>_$类名FromJson</code>(私有函数,.g.dart 内部使用)</td><td><code>_$LoginResponseFromJson(json)</code></td></tr>
<tr><td><code>@ApiRequest(...)</code> on Request 类<br/>ApiRequestGenerator 生成 mixin</td><td><code>_$类名Api</code>mixin</td><td><code>_$LoginRequestApi</code></td></tr>
</tbody>
</table>