Flutter Laravel JSON API集成插件laravel_json_api的使用
Flutter Laravel JSON API 集成插件 laravel_json_api
的使用
Laravel Json Api
这个插件是为了消费基于 Laravel 并使用 cloudcreativity/laravel-json-api
包实现的符合 JSON:API 规范的 API 而创建的。
特性
- 模式(Schemas)
- 自定义头部(Accept, Content-Type, Authorization 等)
- JSON:API 格式化器
- HTTP 请求(GET, POST, PATCH, DELETE, PUT)
- 过滤资源
- 获取关联资源
- 获取关系
- 异常处理
安装
在 Dart 中安装:
dart pub add laravel_json_api
在 Flutter 中安装:
flutter pub add laravel_json_api
使用
连接到我们的服务器
import 'package:laravel_json_api/laravel_json_api.dart';
Adapter adapter = ApiController('www.host.com', '/api/v1');
(不需要添加 http 或 https 协议)
为了在整个应用程序中使用适配器,我们可以将其包装在一个状态处理器中。我们推荐使用 provider
包。
头部
默认情况下,以下头部的值如下:
Header | Value |
---|---|
Accept | application/vnd.api+json |
Content-Type | application/vnd.api+json |
但它们可以被覆盖。
import 'package:laravel_json_api/laravel_json_api.dart';
ApiController controller = ApiController('www.host.com', '/api/v1');
print(controller.headers);
controller.addHeader('Authorization', 'Bearer token');
controller.addHeader('Accept', 'application/json');
controller.addHeader('Content-Type', 'application/json');
print(controller.headers);
Adapter adapter = controller;
创建模式
模式提供了获取器和设置器,帮助我们将响应转换为具有自身属性、关系、关联对象和错误的对象。
以一个简单的博客为例:
import 'package:laravel_json_api/laravel_json_api.dart';
class Article extends Schema {
// 构造函数
Article(ResourceObject resourceObject) : super(resourceObject);
Article.init(String type) : super.init(type);
// 属性
String get title => getAttribute<String>('title');
set title(String value) => setAttribute<String>('title', value);
String get slug => getAttribute<String>('slug');
set slug(String value) => setAttribute<String>('slug', value);
String get content => getAttribute<String>('content');
set content(String value) => setAttribute<String>('content', value);
String get image => getAttribute<String>('image');
set image(String value) => setAttribute<String>('image', value);
// 关系
String? get authorId => idFor('user');
set author(User model) => setHasOne('author', model);
Object? get relatedAuthor => includedDoc('users', 'user');
String? get categoryId => idFor('category');
set category(Category model) => setHasOne('category', model);
Object? get relatedCategory => includedDoc('categories', 'category');
}
class Category extends Schema {
// 构造函数
Category(ResourceObject resourceObject) : super(resourceObject);
Category.init(String type) : super.init(type);
// 属性
String get name => getAttribute<String>('name');
set name(String value) => setAttribute<String>('name', value);
String get slug => getAttribute<String>('slug');
set slug(String value) => setAttribute<String>('slug', value);
String get image => getAttribute<String>('image_cover');
set image(String value) => setAttribute<String>('image_cover', value);
// 关系
Iterable<String> get articlesId => idsFor('articles');
Iterable<Object> get articles => includedDocs('articles');
}
class User extends Schema {
// 构造函数
User(ResourceObject resourceObject) : super(resourceObject);
User.init(String type) : super.init(type);
// 属性
String get firstName => getAttribute<String>('first_name');
set firstName(String value) => setAttribute<String>('first_name', value);
String get email => getAttribute<String>('email');
set email(String value) => setAttribute<String>('email', value);
// 关系
Iterable<String> get articlesId => idsFor('articles');
Iterable<Object> get articles => includedDocs('articles');
}
所有模式方法
String? idFor(String relationshipName)
String? typeFor(String relationshipName)
Map<String, dynamic> dataForHasOne(String relationshipName)
Iterable<dynamic>? dataForHasMany(String relationshipName)
Iterable<String> idsFor(String relationshipName)
Iterable<ResourceObject> includedDocs(String type, [Iterable<String>? ids])
ResourceObject? includedDoc(String type, String relationshipName)
void clearErrorsFor(String attributeName)
bool get hasErrors
bool attributeHasErrors(String attributeName)
Iterable<String> errorsFor(String attributeName)
void clearErrors()
void addErrorFor(String attributeName, String errorMessage)
void setHasOne(String relationshipName, LaravelJsonApiModel model)
获取数据
所有这些操作都是异步的,并返回特定值。
查找单个
Future<Article> getOneArticle(String id) async {
Article article = Article(await adapter.find('articles', id) as ResourceObject);
return article;
}
GET | https://www.host.com/api/v1/articles/1
可选地,我们可以发送 forceReload
参数来缓存此资源,并使用 queryParams
参数进行排序或包含关系。
Future<Article> getOneArticle(String id) async {
Article article = Article(await adapter.find('articles', id,
forceReload: true,
queryParams: {'include': 'category,user'}) as ResourceObject);
return article;
}
GET | https://www.host.com/api/v1/articles/1?include=category,user
查找所有
Future<Iterable<Article>> getAllArticles() async {
Iterable<Article> articles = (await adapter.findAll('articles'))
.map<Article>((article) => Article(article as ResourceObject))
.toList();
return articles;
}
GET | https://www.host.com/api/v1/articles
更多获取请求
Future<Iterable<Object>> findManyById(String endpoint, Iterable<String> ids, {Map<String, String> queryParams})
Future<Iterable<Object>> getRelated(String endpoint, String id, String relationshipName)
Future<Iterable<Object>> filter(String endpoint, String filterField, Iterable<String> values, {Map<String, String> queryParams})
写入数据
Article article = Article.init('articles');
article.title = 'Title';
article.content = 'Content';
article.user = user;
article.category = category;
创建资源
Future saveArticle(Article article) async {
await adapter.save('articles', article.jsonApiDoc);
}
更新资源
Article article = Article(await adapter.find('articles', '1') as ResourceObject);
article.title = 'Title Update';
await adapter.save('articles', article.jsonApiDoc);
替换关系
Article article = Article(await adapter.find('articles', '1') as ResourceObject);
Category newCategory = Category(await adapter.find('categories', '2') as ResourceObject);
await adapter.replaceRelationship('articles', 'category', article, newCategory);
删除资源
Article article = Article(await adapter.find('articles', '1') as ResourceObject);
await adapter.delete('articles', article);
示例代码
示例代码
import 'package:laravel_json_api/laravel_json_api.dart';
// 主函数
void main() async {
ApiController controller = ApiController('maeth.herokuapp.com', '/api/v1');
controller.addHeader(
'Authorization', 'Bearer 32|nEbOJRQUB4jSU9Zh2BcWLqKEpPWQ73hVPbKcZsFn');
Adapter adapter = controller;
// 获取用户
User user = await _getUser(adapter);
print(user);
// 获取分类
Iterable<Category> categories = await _getCategories(adapter);
print(categories.first);
// 创建文章
Article newArticle = Article.init('articles');
newArticle.title = 'Test 1';
newArticle.slug = 'title-1';
newArticle.content = 'Content test 1';
newArticle.image =
'https://res.cloudinary.com/maeth/image/upload/v1638752850/articles/cbogi4o5mny0iggmt1j4.jpg';
newArticle.author = user;
newArticle.category = categories.first;
var response = await _saveArticle(adapter, newArticle.resourceObject);
if (response == true) {
print('Article created');
} else {
print('Article not created');
print(response);
}
print(user.articles);
}
Future<User> _getUser(Adapter adapter) async {
return User(await adapter.find(
'users', '3c85faf7-eacb-4b6b-8547-4e5bd2b24c3f',
queryParams: {'include': 'articles'}) as ResourceObject);
}
Future<Iterable<Category>> _getCategories(Adapter adapter) async {
return (await adapter.findAll('categories'))
.map<Category>((category) => Category(category as ResourceObject))
.toList();
}
Future _saveArticle(Adapter adapter, Object model) async {
try {
Article(await adapter.save('articles', model) as ResourceObject);
return true;
} catch (e) {
print(e);
Article temp = Article(model as ResourceObject);
return temp.errors.first['detail'];
}
}
// 模型类
class Article extends Schema {
// 构造函数
Article(ResourceObject resourceObject) : super(resourceObject);
Article.init(String type) : super.init(type);
// 属性
String get title => getAttribute<String>('title');
set title(String value) => setAttribute<String>('title', value);
String get slug => getAttribute<String>('slug');
set slug(String value) => setAttribute<String>('slug', value);
String get content => getAttribute<String>('content');
set content(String value) => setAttribute<String>('content', value);
String get image => getAttribute<String>('image');
set image(String value) => setAttribute<String>('image', value);
// 关系
String? get authorId => idFor('user');
set author(User model) => setHasOne('author', model);
Object? get relatedAuthor => includedDoc('users', 'user');
String? get categoryId => idFor('category');
set category(Category model) => setHasOne('category', model);
Object? get relatedCategory => includedDoc('categories', 'category');
}
class Category extends Schema {
// 构造函数
Category(ResourceObject resourceObject) : super(resourceObject);
Category.init(String type) : super.init(type);
// 属性
String get name => getAttribute<String>('name');
set name(String value) => setAttribute<String>('name', value);
String get slug => getAttribute<String>('slug');
set slug(String value) => setAttribute<String>('slug', value);
String get image => getAttribute<String>('image_cover');
set image(String value) => setAttribute<String>('image_cover', value);
// 关系
Iterable<String> get articlesId => idsFor('articles');
Iterable<Object> get articles => includedDocs('articles');
}
class User extends Schema {
// 构造函数
User(ResourceObject resourceObject) : super(resourceObject);
User.init(String type) : super.init(type);
// 属性
String get firstName => getAttribute<String>('first_name');
set firstName(String value) => setAttribute<String>('first_name', value);
String get email => getAttribute<String>('email');
set email(String value) => setAttribute<String>('email', value);
// 关系
Iterable<String> get articlesId => idsFor('articles');
Iterable<Object> get articles => includedDocs('articles');
}
更多关于Flutter Laravel JSON API集成插件laravel_json_api的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter Laravel JSON API集成插件laravel_json_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter应用中集成Laravel后端并使用laravel_json_api
插件进行JSON API通信的示例代码。这个示例将涵盖基本的CRUD(创建、读取、更新、删除)操作。
前置条件
- Laravel后端:确保你的Laravel项目已经设置好,并且有一个资源(例如
User
)可以通过API进行访问。 - Flutter前端:确保你的Flutter开发环境已经搭建好。
步骤1:安装laravel_json_api
插件
在Flutter项目的pubspec.yaml
文件中添加laravel_json_api
依赖:
dependencies:
flutter:
sdk: flutter
laravel_json_api: ^最新版本号 # 请替换为实际的最新版本号
然后运行flutter pub get
来安装依赖。
步骤2:配置Laravel后端
确保你的Laravel后端已经安装了laravel-json-api/core
包,并且配置了一个资源。例如,配置User
资源:
composer require laravel-json-api/core
在config/api.php
中注册你的资源:
'resources' => [
'users' => \App\Http\Api\V1\Models\User::class,
],
创建对应的API控制器和路由,通常这些可以通过laravel-json-api
包自动生成。
步骤3:Flutter前端代码示例
以下是一个简单的Flutter应用,它使用laravel_json_api
插件与Laravel后端进行通信。
main.dart
import 'package:flutter/material.dart';
import 'package:laravel_json_api/laravel_json_api.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Laravel JSON API Integration',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final LaravelJsonApiClient client = LaravelJsonApiClient(
baseUrl: 'http://your-laravel-api-url.com/api/v1',
headers: {'Accept': 'application/vnd.api+json'},
);
List<dynamic> users = [];
@override
void initState() {
super.initState();
fetchUsers();
}
void fetchUsers() async {
try {
final response = await client.get('users');
setState(() {
users = response.data.data;
});
} catch (e) {
print(e);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Users List'),
),
body: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(users[index]['attributes']['name']),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
deleteUser(users[index]['id']);
},
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => UserDetailPage(user: users[index])),
);
},
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => UserCreatePage(client: client)),
);
},
tooltip: 'Add User',
child: Icon(Icons.add),
),
);
}
void deleteUser(String id) async {
try {
await client.delete('users/$id');
setState(() {
users.removeWhere((user) => user['id'] == id);
});
} catch (e) {
print(e);
}
}
}
class UserDetailPage extends StatefulWidget {
final dynamic user;
UserDetailPage({required this.user});
@override
_UserDetailPageState createState() => _UserDetailPageState();
}
class _UserDetailPageState extends State<UserDetailPage> {
final TextEditingController nameController = TextEditingController();
@override
void initState() {
super.initState();
nameController.value = TextEditingValue(text: widget.user['attributes']['name']);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('User Detail'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextField(
controller: nameController,
decoration: InputDecoration(labelText: 'Name'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () async {
try {
final response = await client.patch(
'users/${widget.user['id']}',
data: {
'data': {
'type': 'users',
'id': widget.user['id'],
'attributes': {'name': nameController.text},
},
},
);
Navigator.pop(context);
} catch (e) {
print(e);
}
},
child: Text('Update'),
),
],
),
),
);
}
}
class UserCreatePage extends StatefulWidget {
final LaravelJsonApiClient client;
UserCreatePage({required this.client});
@override
_UserCreatePageState createState() => _UserCreatePageState();
}
class _UserCreatePageState extends State<UserCreatePage> {
final TextEditingController nameController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Create User'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextField(
controller: nameController,
decoration: InputDecoration(labelText: 'Name'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () async {
try {
final response = await widget.client.post(
'users',
data: {
'data': {
'type': 'users',
'attributes': {'name': nameController.text},
},
},
);
Navigator.popAndPushNamed(context, '/');
} catch (e) {
print(e);
}
},
child: Text('Create'),
),
],
),
),
);
}
}
解释
- LaravelJsonApiClient初始化:在
_MyHomePageState
类中初始化LaravelJsonApiClient
,设置基础URL和请求头。 - 获取用户列表:
fetchUsers
方法通过GET请求获取用户列表,并更新UI。 - 创建用户:
UserCreatePage
类允许用户输入名称并提交,通过POST请求创建新用户。 - 查看/编辑用户详情:
UserDetailPage
类显示用户详情,并允许用户更新名称,通过PATCH请求更新用户信息。 - 删除用户:在用户列表中,点击删除按钮通过DELETE请求删除用户。
这个示例提供了一个基础框架,你可以根据实际需求进行扩展和修改。