问题描述
在我的项目开发过程中,我将 Flutter 与 graphql 一起使用,出于测试目的,我在操场上尝试了突变并通过了测试,但是在设备和模拟器上收到了 5xx 的错误响应,我知道这是“服务器端”错误,但经过测试来自我们网页的相同突变,它也有效。 除了颤振,我还使用以下软件包:
- 等同:^1.2.5
- gql:^0.12.4
- graphql:^4.0.0
- graphql_Flutter:^4.0.1
- json_annotation: ^3.1.1
- 元:^1.3.0
- 阿尔忒弥斯:^6.18.4
- build_runner:^1.11.1
- json_serializable:^3.5.1
到目前为止,在这个项目中,我使用这个文件语法成功运行了近 10 个突变:
- 我的项目/
注册.graphql
mutation signUp(
$company_name:String!,$email: String!,$firstname: String!,$lastname: String!,$phone: String!,$tin_ein_number: String!,) {
createShipperUser(
company_name: $company_name,email: $email,firstname: $firstname,lastname: $lastname,phone: $phone,tin_ein_number: $tin_ein_number,) {
id
}
}
注册.dart
Widget buildFormBody(BuildContext context) {
return Mutation(
options: Mutationoptions(
document: SignUpMutation().document,onCompleted: (dynamic resultData) {
if (resultData != null) {
onRegistered();
}
},if (e.linkException != null) {
showSnackbar(context,'Something went wrong,please check your network connection and try again.');
return;
}
final validationErrors = findValidationErrors(
e.graphqlErrors,[
'firstname','lastname','email','phone','tin_ein_number','company_name',],);
if (validationErrors.isNotEmpty) {
setState(() {
firstnameError = validationErrors['firstname'];
surnameError = validationErrors['lastname'];
emailError = validationErrors['email'];
phoneError = validationErrors['phone'];
if (isTin) {
einError = null;
tinError = validationErrors['tin_ein_number'];
} else {
einError = validationErrors['tin_ein_number'];
tinError = null;
}
companyError = validationErrors['company_name'];
});
//Todo text
showSnackbar(context,'Please check entered fields');
} else if (e.graphqlErrors.isNotEmpty) {
showSnackbar(
context,e.graphqlErrors[0].message ?? 'Something went wrong');
} else {
showSnackbar(context,'Something went wrong');
}
builder: (runMutation,result) {
isLoading = result.isLoading;
return Form(
ElevatedButton(
onpressed: () => onSubmitTap(runMutation),child: Text(
'Submit',style: TextStyle(
fontSize: 16,fontWeight: FontWeight.w700),),)
);
void onSubmitTap(RunMutation runMutation) {
hideKeyboard();
if (isLoading) {
return;
}
if (formKey.currentState.validate()) {
formKey.currentState.save();
setState(() {
savedPhone = getPhoneMask(savedPhone);
});
runMutation(SignUpArguments(
company_name: savedCompany,email: savedEmail,phone: savedPhone,tin_ein_number: isTin ? 'tin_$savedTin' : 'ein_$savedEin',firstname: savedFirstname,lastname: savedSurname,).toJson());
}
}
以下是出现 500 错误的突变。
createOffer.graphql
Mutation(
options: Mutationoptions(
document: CreateShipmentMutation().document,errorPolicy: ErrorPolicy.all,update: (GraphQLDataProxy cache,QueryResult result) {
if (result.hasException) {
print(result.exception);
}
},onCompleted: (dynamic resultData) {
if (resultData != null) {
print('completed');
print(resultData);
// onCreated();
}
},onError: (e) {
if (e.linkException != null) {
showSnackbar(context,please check your network connection and try again.');
return;
}
if (e.graphqlErrors.isNotEmpty) {
debugPrint(e.graphqlErrors.toString(),wrapWidth: 1024);
} else {
showSnackbar(context,'Something went wrong');
}
},builder: (runMutation,result) {
isLoading = result.isLoading;
return Card(
child: ElevatedButton(
onpressed: () => onReviewTap(runMutation),style: ElevatedButton.styleFrom(
padding:
EdgeInsets.symmetric(vertical: 14)),child: AnimatedSwitcher(
duration: Duration(milliseconds: 150),child: result.isLoading
? Theme(
data: Theme.of(context).copyWith(
accentColor: Colors.white),child:
const ProgressIndicatorSmall(),)
: Text(
'Review Shipment',style: TextStyle(
fontSize: 16,);
void onReviewTap(RunMutation runMutation) {
final acces = accessories
.map((accessory) {
if (accessory.isChecked) {
return accessory.enumType;
}
})
.where((element) => element != null)
.toList();
final stops = isMultipleStops ? items : p2pitems;
hideKeyboard();
if (isLoading) {
return;
}
runMutation(CreateShipmentArguments(
input: OfferInput(
openPrice: 30,shipment: CreateShipmentInput(
requestedTruckTypes: [
TruckTypesEnum.dryVan,accessorials: [
AccessorialsEnum.twicrequired,AccessorialsEnum.ppe,trailer: TrailerInput(
temperatureMax: 0,temperatureMin: 0,temperatureUnit: TemperatureUnitsEnum.f,items: [
ItemInput(
description: "Items description",weight: WeightInput(
weight: 100,weightUnit: WeightUnitTypesEnum.lb,units: UnitInput(
unitCount: 0,unitType: ItemunitTypesEnum.units,handlingPiece: HandlingPieceInput(
pieceCount: 0,pieceType: ItemPieceTypesEnum.pallets,shortName: "Dem23",loadDescription: "adhjahsdhajsdj",routedistanceMiles: 0.0,routeDurationMinutes: 0,stops: [
CreateStopInput(
appointmentType: AppointmentTypesEnum.alreadyMade,startTime: "2021-05-03T00:00:00+02:00",type: StopTypesEnum.pickup,loadingType: LoadingTypesEnum.live,locationInput: LocationInput(
locationName: "HOUSTON",coordinates:
CoordinatesInput(lat: 29.608774,lng: -95.516164),address: AddressInput(
full:
"14810 Fairway Pines Dr,Missouri City,TX 77489,USA",city: "Missouri City",state: "TX",street: "Fairway Pines Drive",streetNumber: 14810),operationalContact: ContactInput(
contactName: "mr contact",email: "[email protected]",phoneNumber: "862615986",notes: "notes lorem ipsum"),schedulingContact: ContactInput(
contactName: "mr contact",)),CreateStopInput(
appointmentType: AppointmentTypesEnum.toBeMade,startTime: "2021-05-14T05:13:30+00:00",endTime: "2021-04-27T17:35:00+00:00",type: StopTypesEnum.dropoff,locationInput: LocationInput(
locationName: "COSTCO WHO,WEBSTER,TX,coordinates: CoordinatesInput(lat: 29.533604,lng: -95.136843),address: AddressInput(
full: "1310 Jasmine St,Webster,TX 77598,city: "Webster",street: "Jasmine Street",streetNumber: 1310,operationalContact: ContactInput(
contactName: "mr contact",email: "[email protected]",schedulingContact: ContactInput(
contactName: "mr contact",).toJson());
以下是 createOffer 在 Playground 上的硬编码:
mutation CreateShipment (
$input: OfferInput!
) {
createOffer(input: $input){
uuid
shipper_id
}
}
#variables
{
"input": {
"open_price": 30,"shipment": {
"requested_truck_types": [
"DRY_VAN"
],"accessorials": [
"TWIC_required","SHIPPER_REQUIRES_MASK_gloveS","PPE"
],"items": [
{
"description": "Items description","handling_piece": {
"piece_type": "PALLETS","piece_count": 0
},"units": {
"unit_type": "UNITS","unit_count": 0
},"weight": {
"weight": 100,"weight_unit": "LB"
}
}
],"trailer": {
"temperature_max": 0,"temperature_min": 0,"temperature_unit": "F"
},"short_name": "Dem","load_description": "load descriotajj adaksdjad","route_distance_miles": 0.0,"route_duration_minutes": 0,"stops": [
{
"appointment_type": "ALREADY_MADE","start_time": "2021-05-03T00:00:00+02:00","type": "PICKUP","loading_type": "LIVE","location_input": {
"location_name": "HOUSTON","coordinates": {
"lat": 29.608774,"lng": -95.516164
},"address": {
"full": "14810 Fairway Pines Dr,"city": "Missouri City","state": "TX","street": "Fairway Pines Drive","street_number" :14810
},"operational_contact": {
"contact_name" : "mr contact","email" : "[email protected]","phone_number" : "862615986","notes" : "notes lorem ipsum"
},"scheduling_contact": {
"contact_name" : "mr contact","notes" : "notes lorem ipsum"
}
}
},{
"appointment_type": "TO_BE_MADE","start_time": "2021-05-14T05:13:30+00:00","end_time": "2021-04-27T17:35:00+00:00","type": "DROPOFF","location_input": {
"location_name": "COSTCO WHO,"coordinates": {
"lat": 29.533604,"lng": -95.136843
},"address": {
"full": "1310 Jasmine St,"city": "Webster","street": "Jasmine Street","street_number" :1310
},"email" : "[email protected]","notes" : "notes lorem ipsum"
}
}
}
]
}
}
}
和响应
{
"data": {
"createOffer": {
"uuid": "933eee0a-8x82-46d6-xxx-018xxxxxxx40","shipper_id": "3"
}
},"extensions": {
"lighthouse_subscriptions": {
"version": 1,"channel": null,"channels": []
}
}
}
为了检查是否工作 graphql 验证,我在开始时间/结束时间的日期时间犯了错误并得到这个:
{
"errors": [
{
"message": "Variable \"$input\" got invalid value {\"open_price\":30,\"shipment\":{\"requested_truck_types\":[\"DRY_VAN\"],\"accessorials\":[\"TWIC_required\",\"SHIPPER_REQUIRES_MASK_gloveS\",\"PPE\"],\"items\":[{\"description\":\"Items description\",\"handling_piece\":{\"piece_type\":\"PALLETS\",\"piece_count\":0},\"units\":{\"unit_type\":\"UNITS\",\"unit_count\":0},\"weight\":{\"weight\":100,\"weight_unit\":\"LB\"}}],\"trailer\":{\"temperature_max\":0,\"temperature_min\":0,\"temperature_unit\":\"F\"},\"short_name\":\"Dem\",\"load_description\":\"load descriotajj adaksdjad\",\"route_distance_miles\":0,\"route_duration_minutes\":0,\"stops\":[{\"appointment_type\":\"ALREADY_MADE\",\"start_time\":\"2021-05-03T00:00:00\",\"type\":\"PICKUP\",\"loading_type\":\"LIVE\",\"location_input\":{\"location_name\":\"HOUSTON\",\"coordinates\":{\"lat\":29.608774,\"lng\":-95.516164},\"address\":{\"place_id\":\"EjQxNDgxMCBGYWlyd2F5IFBpbmVzIERyLCBNaXNzb3VyaSBDaXR5LCBUWCA3NzQ4OSwgVVNB\",\"full\":\"14810 Fairway Pines Dr,USA\",\"city\":\"Missouri City\",\"state\":\"TX\",\"street\":\"Fairway Pines Drive\",\"street_number\":14810},\"operational_contact\":{\"contact_name\":\"mr contact\",\"email\":\"[email protected]\",\"phone_number\":\"862615986\",\"notes\":\"notes lorem ipsum\"},\"scheduling_contact\":{\"contact_name\":\"mr contact\",\"notes\":\"notes lorem ipsum\"}}},{\"appointment_type\":\"TO_BE_MADE\",\"start_time\":\"2021-05-14T05:13:30+00:00\",\"end_time\":\"2021-04-27T17:35:00+00:00\",\"type\":\"DROPOFF\",\"location_input\":{\"location_name\":\"COSTCO WHO,\"coordinates\":{\"lat\":29.533604,\"lng\":-95.136843},\"address\":{\"full\":\"1310 Jasmine St,\"city\":\"Webster\",\"street\":\"Jasmine Street\",\"street_number\":1310},\"notes\":\"notes lorem ipsum\"}}}]}}; Expected type DateTimeTz at value.shipment.stops[0].start_time; \"Data missing\"","extensions": {
"category": "graphql"
},"locations": [
{
"line": 1,"column": 25
}
]
}
],"channels": []
}
}
}
这意味着我发送的所有字段都是正确的,我想。也许请求的字段类型正在接受我的有效输入类型,但在工作/解析它们时导致错误,我不知道,我为此苦苦挣扎了将近一周,正如您所看到的,两个硬代码(颤振/操场)是相同的.我的文本字段和其他输入已准备就绪,但我无法首先运行硬编码:/顺便说一句,这不是过期令牌,因为我收到了未经授权的操作错误。
解决方法
终于可以解决这个问题了。解析来自我这边的数据时,后端出现问题。这是数据流:
- 用户输入数据
- 变异前,flutter解析数据和graphql_flutter变异
- 然后,如果一切正常,后端(在我们的例子中是 php)进行字段验证,然后,如果没有,则向客户端发送验证错误。
- 毕竟,服务器开始在 db 上存储数据(这里是关键点)
我的问题发生在最后阶段,不必要的模型属性被发送为空,我们通过阅读 laravel.log 中的日志来了解这一点,因此删除该字段并迁移数据库,最后下载并使用“新”schema.graphql 来自游乐场解决了这个问题。我希望这会在以后有所帮助:)