Flutter RESTful API请求插件brick_rest的使用
Flutter RESTful API 请求插件 brick_rest
的使用
在本指南中,我们将探讨如何在 Flutter 应用程序中使用 brick_rest
插件来处理 RESTful API 请求。该插件提供了一种简单的方式来与 RESTful API 进行交互,并且可以与 brick_core
和 brick_offline_first_with_rest_build
等其他插件结合使用。
REST 提供者
brick_rest
通过 RESTful API 连接 brick
。它提供了与 RESTful API 进行交互的功能,并允许你在应用程序中轻松地管理数据。
支持的查询配置
providerArgs
providerArgs
参数允许你指定关于请求的信息,例如 HTTP 方法或顶级键。
'providerArgs': (
'request': RestRequest(
// 配置请求信息
)
)
where
RestProvider
不支持任何 Query#where
参数。这些参数应根据模型按模型基础进行配置。
模型
@RestSerializable(requestTransformer:)
每个 REST API 的构建方式都不同,并且可能存在技术债务。brick
提供了灵活性,可以在任何系统中处理不一致的端点。端点也可以根据查询更改。
由于 Dart 要求注解为常量,因此无法使用动态函数。这可能会导致一些问题。相反,可以使用 const
构造函数撕裂以在运行时基于查询参数或 Dart 实例(仅限 upsert
和 delete
)动态定义请求(方法、顶级键、URL 等)。
class UserRequestTransformer extends RestRequestTransformer {
final get = const RestRequest(url: '/users');
const UserRequestTransformer(Query? query, RestModel? instance) : super(query, instance);
}
@ConnectOfflineFirstWithRest(
restConfig: RestSerializable(
requestTransformer: UserRequestTransformer.new;
)
)
class User extends OfflineFirstModel {}
不同的提供者调用将使用不同的转换器字段:
class UserRequestTransformer extends RestRequestTransformer {
final get = const RestRequest(url: '/users');
final delete = RestRequest(url: '/users/${instance.id}');
const UserRequestTransformer(Query? query, Model? instance) : super(query, instance);
}
@ConnectOfflineFirstWithRest(
restConfig: RestSerializable(
requestTransformer: UserRequestTransformer.new,
)
)
class User extends OfflineFirstModel {}
如果 RestRequestTransform
的方法字段(get
、upsert
、delete
)为 null
或其 url
为 null
,则提供者将跳过请求。
使用 Query#providerArgs
class UserRequestTransformer extends RestRequestTransformer {
RestRequest? get get {
if (query?.providerArgs.isNotEmpty && query.limit != null) {
return RestRequest(url: "/users?limit=${query.limit}");
}
const RestRequest(url: '/users');
}
final delete = RestRequest(url: '/users/${instance.id}');
const UserRequestTransformer(Query? query, RestModel? instance) : super(query, instance);
}
@ConnectOfflineFirstWithRest(
restConfig: RestSerializable(
requestTransformer: UserRequestTransformer.new,
)
)
class User extends OfflineFirstModel {}
使用 Query#where
class UserRequestTransformer extends RestRequestTransformer {
RestRequest? get get {
if (query?.where != null) {
final id = Where.firstByField('id', query.where)?.value;
if (id != null) return RestRequest(url: "/users/$id");
}
const RestRequest(url: '/users');
}
final delete = RestRequest(url: '/users/${instance.id}');
const UserRequestTransformer(Query? query, RestModel? instance) : super(query, instance);
}
@ConnectOfflineFirstWithRest(
restConfig: RestSerializable(
requestTransformer: UserRequestTransformer.new,
)
)
class User extends OfflineFirstModel {}
为了便于说明,代码被假定为转换器和模型逻辑在同一文件中。强烈建议将请求转换器逻辑包含在其自己的文件中(例如 user.model.request.dart
)。
@RestRequest(topLevelKey:)
数据通常会在 JSON 响应中的顶级键下嵌套。键由以下优先级决定:
Query#providerArgs['request']
中的topLevelKey
,其值非空。RestRequest
中定义的topLevelKey
。- 发现的第一个键。由于映射本质上是一个无序列表,因此依赖于此回退是不推荐的。
class UserRequestTransformer extends RestRequestTransformer {
final get = const RestRequest(url: '/users', topLevelKey: 'users');
final upsert = const RestRequest(url: '/users', topLevelKey: 'user');
const UserRequestTransformer(Query? query, RestModel? instance) : super(query, instance);
}
@ConnectOfflineFirstWithRest(
requestTransformer: UserRequestTransformer.new
)
class User extends OfflineFirstModel {}
如果来自 REST 的响应不是映射,则返回整个响应。
@RestSerializable(fieldRename:)
brick
通过假设标准命名约定减少了将 REST 键映射到模型字段名称的需求。例如:
RestSerializable(fieldRename: FieldRename.snake_case)
// 在从 REST 获取时
"last_name" => final String lastName
// 在向 REST 更新时
final String lastName => "last_name"
字段
@Rest(enumAsString:)
brick
默认假设 REST API 会以与 Flutter 应用程序中的枚举匹配的索引作为整数形式传递。但是,如果你的 API 传递字符串而不是整数,可以通过简单的注解而不编写自定义生成器来处理这种情况。
给定 API:
{ "user": { "hats": ["bowler", "birthday"] } }
只需将 hats
转换为 Dart 枚举:
enum Hat { baseball, bowler, birthday }
...
@Rest(enumAsString: true)
final List<Hat> hats;
@Rest(name:)
REST 键可以根据字段重命名。这将覆盖由 RestSerializable#fieldRename
设置的默认值。
// "full_name" 在从和到 REST 请求中使用,而不是 "last_name"
@Rest(name: "full_name")
final String lastName;
@Rest(ignoreFrom:)
和 @Rest(ignoreTo:)
当为 true
时,字段将被适配器中的(反)序列化函数忽略。
GZIP 请求压缩
所有对 API 端点的请求都可以使用 Dart 的标准 GZip 库进行压缩。所有请求将覆盖 Content-Encoding
头为 {'Content-Encoding': 'gzip'}
。
import 'package:brick_rest/gzip_http_client.dart';
final restProvider = RestProvider(client: GZipHttpClient(level: 9));
注意:你的 API 必须能够接受并解码 GZipped 请求。
不支持的字段类型
以下字段类型未序列化为 REST。但是,不支持的类型仍然可以在模型中作为非最终字段访问。
- 嵌套
List<>
例如<List<List<int>>>
- 多对多关联
完整示例代码
以下是完整的示例代码,展示了如何在 Flutter 应用程序中使用 brick_rest
插件。
import 'package:brick_core/core.dart';
import 'package:brick_rest/brick_rest.dart';
/// 这个类和代码总是由生成器生成。
/// 它在这里作为示例包含。
/// Rest 适配器由利用 `brick_rest_generators` 包的域生成,
/// 例如 `brick_offline_first_with_rest_build`
class UserAdapter extends RestAdapter<User> {
[@override](/user/override)
Future<User> fromRest(data, {required provider, repository}) async {
return User(
name: data['name'],
);
}
[@override](/user/override)
Future<Map<String, dynamic>> toRest(instance, {required provider, repository}) async {
return {
'name': instance.name,
};
}
}
/// 这个值总是由生成器生成。
/// 它在这里作为示例包含。
/// 从你的应用中导入 `lib/brick/brick.g.dart`
final dictionary = RestModelDictionary({
User: UserAdapter(),
});
/// 模型是唯一的,具体取决于实现(例如 Flutter 应用)
class User extends RestModel {
final String name;
User({
required this.name,
});
}
class MyRepository extends SingleProviderRepository<RestModel> {
MyRepository(String baseApiUrl)
: super(
RestProvider(
baseApiUrl,
modelDictionary: dictionary,
),
);
}
void main() async {
final repository = MyRepository('http://localhost:8080');
final users = await repository.get<User>();
print(users);
}
更多关于Flutter RESTful API请求插件brick_rest的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter RESTful API请求插件brick_rest的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter中使用brick_rest
插件来进行RESTful API请求的示例代码。brick_rest
是一个用于简化HTTP请求的Flutter插件。
首先,你需要在你的pubspec.yaml
文件中添加brick_rest
依赖:
dependencies:
flutter:
sdk: flutter
brick_rest: ^最新版本号 # 请替换为最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,你可以在Flutter项目中使用brick_rest
来进行API请求。以下是一个完整的示例,展示了如何进行GET和POST请求:
import 'package:flutter/material.dart';
import 'package:brick_rest/brick_rest.dart';
import 'dart:convert';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter brick_rest Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String? responseData;
String? errorMessage;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('brick_rest Example'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextButton(
onPressed: () => fetchData(),
child: Text('Fetch Data (GET)'),
),
SizedBox(height: 16),
TextButton(
onPressed: () => postData(),
child: Text('Post Data (POST)'),
),
SizedBox(height: 16),
if (responseData != null)
Text(
'Response Data:\n$responseData',
style: TextStyle(fontSize: 16),
),
if (errorMessage != null)
Text(
'Error:\n$errorMessage',
style: TextStyle(fontSize: 16, color: Colors.red),
),
],
),
),
);
}
void fetchData() async {
try {
var response = await BrickRest.get(
url: 'https://jsonplaceholder.typicode.com/posts/1',
);
if (response.statusCode == 200) {
setState(() {
responseData = jsonEncode(jsonDecode(response.body));
errorMessage = null;
});
} else {
setState(() {
responseData = null;
errorMessage = 'Failed to fetch data. Status code: ${response.statusCode}';
});
}
} catch (e) {
setState(() {
responseData = null;
errorMessage = e.toString();
});
}
}
void postData() async {
try {
var response = await BrickRest.post(
url: 'https://jsonplaceholder.typicode.com/posts',
body: jsonEncode({
'title': 'foo',
'body': 'bar',
'userId': 1,
}),
headers: {
'Content-Type': 'application/json',
},
);
if (response.statusCode == 201) {
setState(() {
responseData = jsonEncode(jsonDecode(response.body));
errorMessage = null;
});
} else {
setState(() {
responseData = null;
errorMessage = 'Failed to post data. Status code: ${response.statusCode}';
});
}
} catch (e) {
setState(() {
responseData = null;
errorMessage = e.toString();
});
}
}
}
在这个示例中,我们创建了一个简单的Flutter应用,包含两个按钮:一个用于执行GET请求,另一个用于执行POST请求。GET请求从https://jsonplaceholder.typicode.com/posts/1
获取一个帖子,而POST请求向https://jsonplaceholder.typicode.com/posts
发送一个新的帖子。
请注意,BrickRest.get
和BrickRest.post
方法返回的是一个Response
对象,你可以检查其statusCode
属性来确定请求是否成功,并读取body
属性来获取响应数据。
请确保替换示例中的URL和请求体数据以匹配你的实际API端点和数据需求。