Flutter Directus API管理插件directus_api_manager的使用
Flutter Directus API管理插件directus_api_manager的使用
特性
此包可以为你的每个Directus集合生成模型类。
安装
在你的 pubspec.yaml
文件中添加该包作为依赖:
dependencies:
flutter:
sdk: flutter
directus_api_manager:
git: https://github.com/maxbritto/directus_api_manager.git
如果你想要使用特定版本,可以在 git
之后添加 version
字段:
dependencies:
directus_api_manager:
git: https://github.com/maxbritto/directus_api_manager.git
version: ^1.2.0
开始使用
创建你的模型
为每个Directus模型创建一个新的类,继承自 DirectusItem
并使用注解指定 endpointName
:
[@DirectusCollection](/user/DirectusCollection)()
[@CollectionMetadata](/user/CollectionMetadata)(endpointName: "player")
class PlayerDirectusModel extends DirectusItem {
PlayerDirectusModel.newItem({required String nickname}) : super.newItem() {
setValue(nickname, forKey: "nickname");
}
PlayerDirectusModel(super.rawReceivedData);
String get nickname => getValue(forKey: "nickname");
int? get bestScore => getValue(forKey: "best_score");
set bestScore(int? newBestScore) => setValue(newBestScore, forKey: "best_score");
}
重要提示:你必须包含一个初始化方法,该方法调用父类的初始化方法并传递接收到的原始数据,而不能添加其他参数:
PlayerDirectusModel(super.rawReceivedData);
如果需要创建新项目并发送到服务器,应该覆盖名为 newItem()
的初始化方法:
PlayerDirectusModel.newItem() : super.newItem();
你可以根据需要添加任何属性作为计算属性,以访问数据:
String get nickname => getValue(forKey: "nickname");
int get bestScore => getValue(forKey: "best_score");
set bestScore(int newBestScore) => setValue(newBestScore, forKey: "best_score");
注意:键名必须与Directus集合中的属性名称相同,并且类型也必须一致。
为你的模型生成代码
每次添加新的集合时,可以通过运行以下命令触发代码生成器:
dart run build_runner build lib
这将为你项目的目录添加新的 .reflectable.dart
文件。不要将这些文件包含在git仓库中。
建议:在 .gitignore
文件末尾添加以下行:
*.reflectable.dart
初始化库以使用生成的模型
在 main()
函数中初始化反射:
void main() {
initializeReflectable();
//...
// 其余应用代码
}
创建你的DirectusApiManager
这个对象将处理所有事情,包括身份验证、令牌管理、发送请求、解析响应等。你应该只创建一个这种类型的对象,并且只需要提供你的Directus实例的URL:
DirectusApiManager _directusApiManager = DirectusApiManager(baseURL: "http://0.0.0.0:8055/");
管理用户和认证
在进行需要授权的请求之前,使用 loginDirectusUser
方法进行认证:
final apiManager = DirectusApiManager(baseURL: "http://0.0.0.0:8055/");
final result = await apiManager.loginDirectusUser("will@acn.com", "will-password");
if (result.type == DirectusLoginResultType.success) {
print("User logged in");
} else if (result.type == DirectusLoginResultType.invalidCredentials) {
print("Please verify entered credentials");
} else if (result.type == DirectusLoginResultType.invalidOTP) {
print("Please provide OTP");
// 保留邮箱和密码,进入下一个屏幕或额外字段并重新提交
// await apiManager.loginDirectusUserWithOtp("will@acn.com", "will-password", "123456");
} else if (result.type == DirectusLoginResultType.error) {
print("An unknown error occurred");
final additionalMessage = result.message;
if (additionalMessage != null) {
print("More information: $additionalMessage");
}
}
如果用户的登录需要MFA/OTP,你需要向用户提供额外的字段或页面来完成认证,并重新发送认证到 loginDirectusUserWithOtp
方法:
final result = await apiManager.loginDirectusUserWithOtp("will@acn.com", "will-password", "123456");
所有未来的请求都会包含此用户令牌。
CRUD操作
对于每个集合,你可以执行以下操作:
- 获取一个或多个项目
- 更新项目
- 创建项目
- 删除项目
创建新项目
final newPlayer = PlayerDirectusModel.newItem(nickname: "Sheldon");
final creationResult = await apiManager.createNewItem(objectToCreate: newPlayer);
if (creationResult.isSuccess) {
print("Created player!");
final createdPlayer = creationResult.createdItem;
// 取决于你的Directus服务器授权,你可能无法访问创建的项目
if (createdPlayer != null) {
print("The id of this new player is ${createdPlayer.id}");
}
} else {
final error = creationResult.error;
if (error != null) {
print("Error while creating player: $error");
}
}
获取现有项目
多个项目
final list = await apiManager.findListOfItems<PlayerDirectusModel>();
for (final player in list) {
print("${player.nickname} - ${player.bestScore}");
}
单个特定项目
final PlayerDirectusModel onePlayer = await apiManager.getSpecificItem(id: "1");
print(onePlayer.nickname);
更新现有项目
final PlayerDirectusModel onePlayer = await apiManager.getSpecificItem(id: "1");
onePlayer.bestScore = 123;
final updatedPlayer = await apiManager.updateItem(objectToUpdate: onePlayer);
WebSocket支持
DirectusWebSocket
DirectusWebSocket
允许通过WebSocket从Directus获取数据。它会处理身份验证、刷新令牌过程,并保持连接活跃。每个 DirectusWebSocket
可以有多个 DirectusWebSocketSubscription
。
DirectusWebSocketSubscription
DirectusWebSocketSubscription
表示对你的Directus服务器的订阅。以下是使用它的必要属性:
uid
必须指定。当服务器发送消息时,将提供此uid。这允许我们知道消息来自哪个订阅。onCreate
、onUpdate
、onDelete
回调会在订阅接收到消息时触发。它们都是可选的,但DirectusWebSocketSubscription
至少需要有一个。
DirectusWebSocketSubscription<DirectusDataExtension>(
uid: "directus_data_extension_uid",
onCreate: onCreate,
onUpdate: onUpdate,
onDelete: onDelete,
sort: const [SortProperty("id")],
limit: 10,
offset: 10,
filter: const PropertyFilter(
field: "folder",
operator: FilterOperator.equals,
value: "folder_id"
)
);
缓存系统
启用和配置缓存系统
此API带有一个缓存系统,可以通过提供 ILocalDirectusCacheInterface
实例来启用,当创建 DirectusApiManager
实例时。
提供的一个现成实现是 JsonCacheEngine
类。它将使用json文件存储数据在一个你选择的文件夹中。例如:
import 'package:path_provider/path_provider.dart';
void main() async {
final directory = await getApplicationCacheDirectory();
final apiManager = DirectusApiManager(
baseURL: "http://0.0.0.0:8055/",
cacheEngine: JsonCacheEngine(cacheFolderPath: "${directory.path}/directus_api_cache")
);
// ...
}
你可以决定替换json文件实现,通过创建并提供你自己的实现,该实现实现了 ILocalDirectusCacheInterface
类。
使用缓存系统进行请求
所有读取请求(如 get
、find
、currentUser
等)现在都有可选参数来配置缓存。默认情况下,大多数这些请求将保存响应,但如果下一次请求失败,则只会使用这些响应。如果你想替换未来响应为本地缓存读取,可以将 canUseCacheForResponse
参数设置为 true
,并调整 maxCacheAge
参数来设置缓存的最大年龄(默认为1天)。这将防止直接调用Directus服务器,如果存在相同的请求的有效缓存。
await sut.getSpecificItem<DirectusItemTest>(
id: "element1",
canUseCacheForResponse: true,
maxCacheAge: const Duration(days: 1)
);
如果你想完全禁用某个请求的缓存,可以将 canSaveResponseToCache
参数设置为 false
。
await sut.getSpecificItem<DirectusItemTest>(
id: "element1",
canSaveResponseToCache: false
);
默认情况下,即使缓存已过期,如果实际网络请求失败,也可以使用过期缓存。如果你想禁用此行为,可以将 canUseOldCachedResponseAsFallback
参数设置为 false
。
await sut.getSpecificItem<DirectusItemTest>(
id: "element1",
canUseOldCachedResponseAsFallback: false
);
这些参数适用于所有基于读取的请求。
额外信息
高级属性
如果你的集合有需要特定解析的高级属性,可以在计算属性中进行处理。例如,在Directus中,属性类型为“标签列表”,我们可以输入一些课程ID作为数字,但Directus将所有标签视为字符串。因此,我们在Dart代码中将其转换如下:
List<int> get requiredCourseIdList {
final courseListJson = getValue(forKey: "required_course_id_list");
if (courseListJson is List<dynamic>) {
return courseListJson
.map<int>((courseIdString) => int.parse(courseIdString))
.toList();
} else {
return [];
}
}
示例代码
import 'package:directus_api_manager/directus_api_manager.dart';
import 'directus_api_manager_example.reflectable.dart';
Future<void> main() async {
initializeReflectable();
final apiManager = DirectusApiManager(baseURL: "http://0.0.0.0:8055/");
// 认证
final loginResult = await apiManager.loginDirectusUser("admin@example.com", "d1r3ctu5");
if (loginResult.type == DirectusLoginResultType.success) {
print("User logged in");
} else if (loginResult.type == DirectusLoginResultType.invalidCredentials) {
print("Please verify entered credentials");
} else if (loginResult.type == DirectusLoginResultType.invalidOTP) {
print("You need to provide a valid OneTimePassword code");
} else if (loginResult.type == DirectusLoginResultType.error) {
print("An unknown error occurred");
final additionalMessage = loginResult.message;
if (additionalMessage != null) {
print("More information: $additionalMessage");
}
}
// 创建新项目
final newPlayer = PlayerDirectusModel.newItem(nickname: "Leonard");
final creationResult = await apiManager.createNewItem(objectToCreate: newPlayer);
if (creationResult.isSuccess) {
print("Created player!");
final createdPlayer = creationResult.createdItem;
// 取决于你的Directus服务器授权,你可能无法访问创建的项目
if (createdPlayer != null) {
print("The id of this new player is ${createdPlayer.id}");
}
} else {
final error = creationResult.error;
if (error != null) {
print("Error while creating player: $error");
}
}
// 多个项目
final list = await apiManager.findListOfItems<PlayerDirectusModel>();
for (final player in list) {
print("${player.nickname} - ${player.bestScore}");
}
final playerId = list.first.id;
if (playerId == null) {
print("No player id found");
return;
}
// 从ID获取单个特定项目
final PlayerDirectusModel? fetchedPlayer = await apiManager.getSpecificItem(id: playerId);
if (fetchedPlayer != null) {
print(fetchedPlayer.nickname);
// 更新项目
fetchedPlayer.bestScore = 123;
final updatedPlayer = await apiManager.updateItem(objectToUpdate: fetchedPlayer);
print(updatedPlayer.bestScore);
}
}
[@DirectusCollection](/user/DirectusCollection)()
[@CollectionMetadata](/user/CollectionMetadata)(endpointName: "player")
class PlayerDirectusModel extends DirectusItem {
PlayerDirectusModel.newItem({required String nickname}) : super.newItem() {
setValue(nickname, forKey: "nickname");
}
PlayerDirectusModel(super.rawReceivedData);
String get nickname => getValue(forKey: "nickname");
int? get bestScore => getValue(forKey: "best_score");
set bestScore(int? newBestScore) => setValue(newBestScore, forKey: "best_score");
}
更多关于Flutter Directus API管理插件directus_api_manager的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter Directus API管理插件directus_api_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用directus_api_manager
插件来管理Directus API的示例代码。这个示例展示了如何初始化插件、进行身份验证以及执行一些基本的CRUD操作。
首先,确保你已经在pubspec.yaml
文件中添加了directus_api_manager
依赖:
dependencies:
flutter:
sdk: flutter
directus_api_manager: ^最新版本号 # 请替换为实际最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,你可以在你的Flutter项目中按照以下步骤使用directus_api_manager
插件:
1. 导入插件并初始化
在你的Dart文件中导入插件,并初始化Directus API客户端:
import 'package:flutter/material.dart';
import 'package:directus_api_manager/directus_api_manager.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: DirectusExample(),
);
}
}
class DirectusExample extends StatefulWidget {
@override
_DirectusExampleState createState() => _DirectusExampleState();
}
class _DirectusExampleState extends State<DirectusExample> {
DirectusClient? _directusClient;
@override
void initState() {
super.initState();
// 初始化Directus客户端
_initDirectusClient();
}
void _initDirectusClient() async {
// 替换为你的Directus实例的URL、项目名称、管理密钥等信息
String directusUrl = 'https://your-directus-instance.com';
String projectName = 'your-project-name';
String adminKey = 'your-admin-key';
DirectusClient client = DirectusClient(
baseUrl: directusUrl,
projectName: projectName,
adminKey: adminKey,
);
setState(() {
_directusClient = client;
});
// 可以在这里添加登录逻辑,如果需要的话
// await _login(client);
}
// Future<void> _login(DirectusClient client) async {
// // 登录逻辑(如果需要的话)
// }
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Directus API Manager Example'),
),
body: Center(
child: _directusClient == null
? CircularProgressIndicator()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => _fetchItems(_directusClient!),
child: Text('Fetch Items'),
),
// 添加其他按钮以执行CRUD操作
],
),
),
);
}
void _fetchItems(DirectusClient client) async {
try {
// 假设我们有一个名为'items'的集合
var response = await client.getItems('items');
print(response.data);
// 处理响应数据
} catch (e) {
print('Error fetching items: $e');
}
}
}
2. 执行CRUD操作
在上面的代码中,我们展示了如何初始化Directus客户端并获取项目中的项。下面是如何执行创建、读取、更新和删除(CRUD)操作的示例:
void _createItem(DirectusClient client, Map<String, dynamic> itemData) async {
try {
var response = await client.createItem('items', itemData);
print('Created item: ${response.data}');
} catch (e) {
print('Error creating item: $e');
}
}
void _updateItem(DirectusClient client, String itemId, Map<String, dynamic> updatedData) async {
try {
var response = await client.updateItem('items', itemId, updatedData);
print('Updated item: ${response.data}');
} catch (e) {
print('Error updating item: $e');
}
}
void _deleteItem(DirectusClient client, String itemId) async {
try {
var response = await client.deleteItem('items', itemId);
print('Deleted item: ${response.data}');
} catch (e) {
print('Error deleting item: $e');
}
}
你可以将这些函数添加到你的_DirectusExampleState
类中,并在相应的按钮点击事件中调用它们。例如:
ElevatedButton(
onPressed: () {
Map<String, dynamic> itemData = {
'name': 'New Item',
// 其他字段
};
_createItem(_directusClient!, itemData);
},
child: Text('Create Item'),
),
这样,你就可以在Flutter应用中通过directus_api_manager
插件与Directus API进行交互了。请根据你的实际需求调整代码中的集合名称、字段和数据。