Flutter Airtable Data [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Exception: 422
Flutter Airtable Data [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Exception: 422
当我尝试更新 Airtable 数据库的某些数据时,出现 [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Exception: 422。
我可以获取、删除但无法更新我的数据。
下面有代码
airtable_data_candidate_http.dart
import 'package:http/http.dart' as http;
import 'package:tinjob/model/airtable_data_candidate.dart';
import 'package:tinjob/model/airtable_data_company.dart';
import 'package:tinjob/utils/config.dart';
class AirtableDataCandidateHttp {
final Uri urlCandidate = Uri.https(
"api.airtable.com",
"/v0/${Config.airtableProjectBase}/candidat",
{"maxRecords": "500", "view": "Grid view"},
);
Future<List<AirtableDataCandidate>> getCandidate() async {
final res = await http.get(
urlCandidate,
headers: {"Authorization": "Bearer ${Config.airtableApikey}"},
);
if (res.statusCode == 200) {
var convertDataToJson = jsonDecode(res.body);
var data = convertDataToJson['records'];
print(data);
List<AirtableDataCandidate> values = [];
data.forEach(
(value) => {
values.add(
AirtableDataCandidate(
id: value['id'],
nom: value['fields']['nom'],
prenom: value['fields']['prenom'],
photo: value['fields']['photo'][0]['url'],
statut: value['fields']['statut'],
mail: value['fields']['mail'],
localisation: value['fields']['localisation'],
telephone: value['fields']['telephone'],
match: value['fields']['match'],
cv: value['fields']['cv'][0]['url'],
lat: value['fields']['lat'].toDouble(),
long: value['fields']['long'].toDouble(),
),
)
},
);
return values;
} else {
print('EEREUR');
throw "ERROR !!!!!";
}
}
// DELETE AIRTABLE CANDIDATE
Future<String> deleteCandidate(String id) async {
final response = await http.delete(
Uri.https(
"api.airtable.com", "/v0/${Config.airtableProjectBase}/candidat/$id"),
headers: {"Authorization": "Bearer ${Config.airtableApikey}"},
body: jsonEncode(<String, String>{}),
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return id;
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception(response.statusCode);
}
}
// Update AIRTABLE CANDIDATE
Future<AirtableDataCandidate> updateCandidate(String id, String match) async {
final response = await http.put(
Uri.https(
"api.airtable.com", "/v0/${Config.airtableProjectBase}/candidat/$id"),
headers: {
"Authorization": "Bearer ${Config.airtableApikey}",
},
body: jsonEncode(<String, String>{
'match': match,
}),
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return AirtableDataCandidate.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception(response.statusCode);
}
}
}
airtable_data_candidate.dart
String id;
String nom;
String prenom;
String photo;
String statut;
String telephone;
String mail;
String localisation;
String cv;
String match;
double lat;
double long;
AirtableDataCandidate({
required this.id,
required this.nom,
required this.prenom,
required this.photo,
required this.statut,
required this.telephone,
required this.mail,
required this.localisation,
required this.cv,
required this.lat,
required this.long,
required this.match,
});
factory AirtableDataCandidate.fromJson(Map<String, dynamic> json) {
return AirtableDataCandidate(
id: json['id'],
nom: json['fields']['nom'],
prenom: json['fields']['prenom'],
photo: json['fields']['photo'][0]['url'],
statut: json['fields']['statut'],
mail: json['fields']['mail'],
localisation: json['fields']['localisation'],
telephone: json['fields']['telephone'],
match: json['fields']['match'],
cv: json['fields']['cv'][0]['url'],
lat: json['fields']['lat'].toDouble(),
long: json['fields']['long'].toDouble(),
);
}
}
swipe.dart --> 我在哪里执行更新操作(如果向左滑动则更新...)
import 'package:flutter/material.dart';
import 'package:flutter_tindercard/flutter_tindercard.dart';
import 'package:tinjob/model/airtable_data_candidate.dart';
import 'package:tinjob/service/airtable_data_candidate_http.dart';
import 'package:tinjob/widgets/widget_drawer.dart';
class SwipeScreen extends StatefulWidget {
const SwipeScreen({Key? key}) : super(key: key);
@override
_SwipeScreenState createState() => _SwipeScreenState();
}
class _SwipeScreenState extends State<SwipeScreen>
with TickerProviderStateMixin {
final AirtableDataCandidateHttp airtableData = AirtableDataCandidateHttp();
List<String> welcomeImages = [];
List<AirtableDataCandidate> candidatesDatas = [];
setPictures() async {
var candidates = await airtableData.getCandidate();
for (var candidate in candidates) {
setState(() {
welcomeImages.add(candidate.photo);
candidatesDatas.add(candidate);
});
}
}
@override
void initState() {
setPictures();
super.initState();
}
@override
Widget build(BuildContext context) {
CardController controller; //Use this to trigger swap.
return new Scaffold(
appBar: AppBar(title: const Text('Les derniers candidats')),
drawer: drawer(context),
body: new Center(
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.6,
child: new TinderSwapCard(
swipeUp: false,
swipeDown: false,
orientation: AmassOrientation.BOTTOM,
totalNum: welcomeImages.length,
stackNum: 3,
swipeEdge: 4.0,
maxWidth: MediaQuery.of(context).size.width * 0.9,
maxHeight: MediaQuery.of(context).size.width * 0.9,
minWidth: MediaQuery.of(context).size.width * 0.8,
minHeight: MediaQuery.of(context).size.width * 0.8,
cardBuilder: (context, index) => Card(
child: Image.network('${welcomeImages[index]}'),
),
cardController: controller = CardController(),
swipeUpdateCallback: (DragUpdateDetails details, Alignment align) {
/// Get swiping card's alignment
if (align.x < 0) {
//Card is LEFT swiping
} else if (align.x > 0) {
//Card is RIGHT swiping
}
},
swipeCompleteCallback:
(CardSwipeOrientation orientation, int index) {
/// Get orientation & index of swiped card!
print('${candidatesDatas[index].match}');
print(orientation);
if (orientation == CardSwipeOrientation.LEFT) {
print('LEFT');
candidatesDatas[index].match = 'Refusé';
print('${candidatesDatas[index].match}');
airtableData.updateCandidate(
candidatesDatas[index].id, candidatesDatas[index].match);
} else if (orientation == CardSwipeOrientation.RIGHT) {
//Card is RIGHT swiping
print('RIGHTEZBI');
candidatesDatas[index].match = 'Admis';
print('${candidatesDatas[index].match}');
}
},
),
),
),
);
}
}
希望有人能找到我的解决方案,我完全不在:(
谢谢!
更新
- 不要把你的 id 放在 Url
- 将Content-Type放入headers
- 更改您的 body 以传递记录,并更新 id + 字段
没有用你的确切结构测试,所以告诉我...
Future<AirtableDataCandidate> updateCandidate(String id, String match) async {
final response = await http.put(
Uri.https(
"api.airtable.com", "/v0/${Config.airtableProjectBase}/candidat/", /* 1 */
),
headers: {
"Authorization": "Bearer ${Config.airtableApikey}",
"Content-Type": "application/json", /* 2 */
},
body: jsonEncode( /* 3 */
{
"records": [
{
"id": $id,
"fields": {
'match': match,
}
},
]
},
),
)
/// etc.
插入(供参考)
- 在POST
- 不要使用 ID...
- 列出您所有的字段...
final response = await http.post /* 1 */ (
Uri.https(
"api.airtable.com", "/v0/${Config.airtableProjectBase}/candidat/",
),
headers: {
"Authorization": "Bearer ${Config.airtableApikey}",
"Content-Type": "application/json",
},
body: jsonEncode(
{
"records": [
{
/* 2 */
"fields": {
"x": "", /* 3 */
"y": "", /* 3 */
"z": "", /* 3 */
}
},
]
},
),
)
当我尝试更新 Airtable 数据库的某些数据时,出现 [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Exception: 422。 我可以获取、删除但无法更新我的数据。
下面有代码
airtable_data_candidate_http.dart
import 'package:http/http.dart' as http;
import 'package:tinjob/model/airtable_data_candidate.dart';
import 'package:tinjob/model/airtable_data_company.dart';
import 'package:tinjob/utils/config.dart';
class AirtableDataCandidateHttp {
final Uri urlCandidate = Uri.https(
"api.airtable.com",
"/v0/${Config.airtableProjectBase}/candidat",
{"maxRecords": "500", "view": "Grid view"},
);
Future<List<AirtableDataCandidate>> getCandidate() async {
final res = await http.get(
urlCandidate,
headers: {"Authorization": "Bearer ${Config.airtableApikey}"},
);
if (res.statusCode == 200) {
var convertDataToJson = jsonDecode(res.body);
var data = convertDataToJson['records'];
print(data);
List<AirtableDataCandidate> values = [];
data.forEach(
(value) => {
values.add(
AirtableDataCandidate(
id: value['id'],
nom: value['fields']['nom'],
prenom: value['fields']['prenom'],
photo: value['fields']['photo'][0]['url'],
statut: value['fields']['statut'],
mail: value['fields']['mail'],
localisation: value['fields']['localisation'],
telephone: value['fields']['telephone'],
match: value['fields']['match'],
cv: value['fields']['cv'][0]['url'],
lat: value['fields']['lat'].toDouble(),
long: value['fields']['long'].toDouble(),
),
)
},
);
return values;
} else {
print('EEREUR');
throw "ERROR !!!!!";
}
}
// DELETE AIRTABLE CANDIDATE
Future<String> deleteCandidate(String id) async {
final response = await http.delete(
Uri.https(
"api.airtable.com", "/v0/${Config.airtableProjectBase}/candidat/$id"),
headers: {"Authorization": "Bearer ${Config.airtableApikey}"},
body: jsonEncode(<String, String>{}),
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return id;
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception(response.statusCode);
}
}
// Update AIRTABLE CANDIDATE
Future<AirtableDataCandidate> updateCandidate(String id, String match) async {
final response = await http.put(
Uri.https(
"api.airtable.com", "/v0/${Config.airtableProjectBase}/candidat/$id"),
headers: {
"Authorization": "Bearer ${Config.airtableApikey}",
},
body: jsonEncode(<String, String>{
'match': match,
}),
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return AirtableDataCandidate.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception(response.statusCode);
}
}
}
airtable_data_candidate.dart
String id;
String nom;
String prenom;
String photo;
String statut;
String telephone;
String mail;
String localisation;
String cv;
String match;
double lat;
double long;
AirtableDataCandidate({
required this.id,
required this.nom,
required this.prenom,
required this.photo,
required this.statut,
required this.telephone,
required this.mail,
required this.localisation,
required this.cv,
required this.lat,
required this.long,
required this.match,
});
factory AirtableDataCandidate.fromJson(Map<String, dynamic> json) {
return AirtableDataCandidate(
id: json['id'],
nom: json['fields']['nom'],
prenom: json['fields']['prenom'],
photo: json['fields']['photo'][0]['url'],
statut: json['fields']['statut'],
mail: json['fields']['mail'],
localisation: json['fields']['localisation'],
telephone: json['fields']['telephone'],
match: json['fields']['match'],
cv: json['fields']['cv'][0]['url'],
lat: json['fields']['lat'].toDouble(),
long: json['fields']['long'].toDouble(),
);
}
}
swipe.dart --> 我在哪里执行更新操作(如果向左滑动则更新...)
import 'package:flutter/material.dart';
import 'package:flutter_tindercard/flutter_tindercard.dart';
import 'package:tinjob/model/airtable_data_candidate.dart';
import 'package:tinjob/service/airtable_data_candidate_http.dart';
import 'package:tinjob/widgets/widget_drawer.dart';
class SwipeScreen extends StatefulWidget {
const SwipeScreen({Key? key}) : super(key: key);
@override
_SwipeScreenState createState() => _SwipeScreenState();
}
class _SwipeScreenState extends State<SwipeScreen>
with TickerProviderStateMixin {
final AirtableDataCandidateHttp airtableData = AirtableDataCandidateHttp();
List<String> welcomeImages = [];
List<AirtableDataCandidate> candidatesDatas = [];
setPictures() async {
var candidates = await airtableData.getCandidate();
for (var candidate in candidates) {
setState(() {
welcomeImages.add(candidate.photo);
candidatesDatas.add(candidate);
});
}
}
@override
void initState() {
setPictures();
super.initState();
}
@override
Widget build(BuildContext context) {
CardController controller; //Use this to trigger swap.
return new Scaffold(
appBar: AppBar(title: const Text('Les derniers candidats')),
drawer: drawer(context),
body: new Center(
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.6,
child: new TinderSwapCard(
swipeUp: false,
swipeDown: false,
orientation: AmassOrientation.BOTTOM,
totalNum: welcomeImages.length,
stackNum: 3,
swipeEdge: 4.0,
maxWidth: MediaQuery.of(context).size.width * 0.9,
maxHeight: MediaQuery.of(context).size.width * 0.9,
minWidth: MediaQuery.of(context).size.width * 0.8,
minHeight: MediaQuery.of(context).size.width * 0.8,
cardBuilder: (context, index) => Card(
child: Image.network('${welcomeImages[index]}'),
),
cardController: controller = CardController(),
swipeUpdateCallback: (DragUpdateDetails details, Alignment align) {
/// Get swiping card's alignment
if (align.x < 0) {
//Card is LEFT swiping
} else if (align.x > 0) {
//Card is RIGHT swiping
}
},
swipeCompleteCallback:
(CardSwipeOrientation orientation, int index) {
/// Get orientation & index of swiped card!
print('${candidatesDatas[index].match}');
print(orientation);
if (orientation == CardSwipeOrientation.LEFT) {
print('LEFT');
candidatesDatas[index].match = 'Refusé';
print('${candidatesDatas[index].match}');
airtableData.updateCandidate(
candidatesDatas[index].id, candidatesDatas[index].match);
} else if (orientation == CardSwipeOrientation.RIGHT) {
//Card is RIGHT swiping
print('RIGHTEZBI');
candidatesDatas[index].match = 'Admis';
print('${candidatesDatas[index].match}');
}
},
),
),
),
);
}
}
希望有人能找到我的解决方案,我完全不在:(
谢谢!
更新
- 不要把你的 id 放在 Url
- 将Content-Type放入headers
- 更改您的 body 以传递记录,并更新 id + 字段
没有用你的确切结构测试,所以告诉我...
Future<AirtableDataCandidate> updateCandidate(String id, String match) async {
final response = await http.put(
Uri.https(
"api.airtable.com", "/v0/${Config.airtableProjectBase}/candidat/", /* 1 */
),
headers: {
"Authorization": "Bearer ${Config.airtableApikey}",
"Content-Type": "application/json", /* 2 */
},
body: jsonEncode( /* 3 */
{
"records": [
{
"id": $id,
"fields": {
'match': match,
}
},
]
},
),
)
/// etc.
插入(供参考)
- 在POST
- 不要使用 ID...
- 列出您所有的字段...
final response = await http.post /* 1 */ (
Uri.https(
"api.airtable.com", "/v0/${Config.airtableProjectBase}/candidat/",
),
headers: {
"Authorization": "Bearer ${Config.airtableApikey}",
"Content-Type": "application/json",
},
body: jsonEncode(
{
"records": [
{
/* 2 */
"fields": {
"x": "", /* 3 */
"y": "", /* 3 */
"z": "", /* 3 */
}
},
]
},
),
)