How to handle errors via Ferry GraphQL - flutter

community!
Please give a clue how to handle GraphQL errors by Ferry.
To simplify let's say that I have toLogin function:
await toLogin(_email, _password);
and it initiates login procedure:
Future<void> sendLogin(String _email, String _password) async {
final _sendLoginRequest = GLoginReq((b) => b
..vars.identifier = _email
..vars.password = _password);
final _client = initClient();
final _storage = GetStorage();
_client.request(_sendLoginRequest).listen((response) {
if (response.hasErrors) {
print('error');
} else {
print('success');
}
});
}
Works fine but I need to add error handling at the main program.
so I add
String _result = await toLogin(_email, _password);
to the main and return to the toLogin();
Future<String> sendLogin(String _email, String _password) async {
final _sendLoginRequest = GLoginReq((b) => b
..vars.identifier = _email
..vars.password = _password);
final _client = initClient();
String _result = 'init';
_client.request(_sendLoginRequest).listen((response) {
if (response.hasErrors) {
print('error');
_result = 'error';
} else {
print('success');
_result = 'success';
}
});
return _result;
}
The problem is that it returns _result before any check and Dart do not allow me to use await
OK, let's try another way:
var _response = OperationResponse(
operationRequest: _sendLoginRequest,
);
var _checkErrors = _response.graphqlErrors;
print(_checkErrors);
But it's always false
I've found option graphqlErrors at OperationResponse but do not have any idea what to fill there.
Please give me a clue how to handle it.
I use Strapi as the backend, the error example is as follows:
{
"errors": [
{
"message": "Bad Request",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"login"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"code": 400,
"data": {
"statusCode": 400,
"error": "Bad Request",
"message": [
{
"messages": [
{
"id": "Auth.form.error.invalid",
"message": "Identifier or password invalid."
}
]
}
],
"data": [
{
"messages": [
{
"id": "Auth.form.error.invalid",
"message": "Identifier or password invalid."
}
]
}
]
},
"stacktrace": [
"Error: Bad Request",
" at checkBadRequest (C:\\Projects\\Zhugory\\zhugory-strapi-graphql\\zhugory-strapi\\node_modules\\strapi-plugin-users-permissions\\config\\schema.graphql.js:13:23)",
" at resolver (C:\\Projects\\Zhugory\\zhugory-strapi-graphql\\zhugory-strapi\\node_modules\\strapi-plugin-users-permissions\\config\\schema.graphql.js:217:11)",
" at runMicrotasks (<anonymous>)",
" at processTicksAndRejections (internal/process/task_queues.js:93:5)"
]
}
}
}
],
"data": null
}

Related

flutter login with dio package

i try to login to the api with dio and i cant handle it
my scenario is:
login with user name,password and server returned session like this:
{
"function": "request_session_generate",
"params": {
"username": "myuser",
"password": "mypass"
}
}
and when send request post method returned session like below code:
{
"result": 0,
"data": {
"session": "mysession...",
"session_status": "generated"
}
}
and second post method for validate this session ... put the session and otp code(google authenticator) like this:
{
"function": "request_session_validate",
"params": {
"session": "mysession",
"otp": "123456"
}
}
when put the session in to the session params server returned:
{
"result": 0,
"data": {
"session": "newSession",
"session_status": "validated"
}
}
how can get the session in the body response first method and use it in the second function for validate
my first function implement code :
class ApiClient {
final Dio _dio = Dio();
Future<Response?> login() async {
try {
Response response = await _dio.post(
'myserver/api',
options: Options(
headers: {
"apikey": "00000000-0000-0000-0000-000000000000",
},
),
data: {
"function": "request_session_generate",
"params": {
"username": "myuser",
"password": "mypass"
}
},
);
//returns the successful user data json object
if(response.statusCode == 200){
return response.data;
}
} on DioError catch (e) {
//returns the error object if any
return e.response!.data;
}
return null;
}
and my implemention for validate and not worked:
Future<Response?> validate() async {
try {
Response responsevalidate = await _dio.post(
'myserver/api',
data: {
"function": "request_session_validate",
"params": {
"session": "mysession",
"otp": "123456"
}
},
);
//returns the successful user data json object
return responsevalidate.data;
} on DioError catch (e) {
//returns the error object if any
return e.response!.data;
}
//IMPLEMENT USER LOGIN
}
how can get session in first function and use it in second function for validate?
use the json decode or something else ?
thank you for help me

HandshakeException: Connection terminated during handshake

I'm developing my first Flutter mobile app, and I'm facing an error trying to fetch data from API REST.
I set 2 get request using HTTP packages:
-the first is a single request, and it's fetching 'work orders' with attributes immediately available;
-the second one is another get request that fires per every 'work order' retrieved from the first request that take others attributes.
Basically, I run the first get request and I made a for loop to fire the second get request for all data.
So, the first request is working fine, instead the second one is giving me the following error for every time it fires:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled
Exception: HandshakeException: Connection terminated during handshake
The strange things are that it works, but I can't anyway render the widget with the error.
This is the code I used for fetching data:
Future<void> fetchAndSetWorkOrders([bool filterByUser = false]) async {
var url = Uri.parse(
'https://API_URL/wo?fields=id,code,description,statusCode,actionType,assignedTo&filter[wo][statusCode]=REQUEST');
try {
var response = await http.get(
url,
headers: {
"token": authToken,
},
);
var extractedData = json.decode(response.body) as Map<String, dynamic>;
final List<WorkOrder> loadedWorkOrders = [];
if (extractedData['data'] == null) {
return;
}
extractedData['data'].forEach(
(attribute) async {
var actionType_url = Uri.parse(attribute['relationships']
['actionType']['links']['related']);
var actionType_response = await http.get(
actionType_url,
headers: {
"token": authToken,
},
);
var actionTypeData = json.decode(actionType_response.body) as dynamic;
var actionType_code =
actionTypeData['data']['attributes']['code'];
print(actionType_code);
loadedWorkOrders.add(
WorkOrder(
id: attribute['id'],
code: attribute['attributes']['code'],
description: attribute['attributes']['description'],
statusCode: attribute['attributes']['statusCode'],
actionType: actionType_code,
),
);
},
);
This is an example of a JSON file I get from the API.
{
"data": [
{
"id": "17db1506f6d-3ca8",
"type": "wo",
"links": {
"self": "https://API_URL/wo/17db1506f6d-3ca8",
"workflow-transitions": "https://API_URL/wo/17db1506f6d-3ca8/workflow-transitions"
},
"attributes": {
"description": "test",
"code": "TEST",
"statusCode": "REQUEST"
},
"relationships": {
"actionType": {
"links": {
"self": "https://API_URL/wo/17db1506f6d-3ca8/relationships/actionType",
"related": "https://API_URL/wo/17db1506f6d-3ca8/actionType"
}
},
"assignedTo": {
"links": {
"self": "https://API_URL/wo/17db1506f6d-3ca8/relationships/assignedTo",
"related": "https://API_URL/wo/17db1506f6d-3ca8/assignedTo"
}
}
}
},
]
}
I hope that someone can help me to solve this problem.

How to set and get data using SharedPreferences?

Previously i do SharedPreferences to get user name. That was okay.
from API Response
"status": 200,
"message": "Login Successfully",
"result": {
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9mYzBhLTIwMi0xODctMy01Lm5ncm9rLmlvXC9hcGlcL2F1dGhcL2xvZ2luIiwiaWF0IjoxNjM5OTAxMDQ0LCJleHAiOjE2Mzk5ODc0NDQsIm5iZiI6MTYzOTkwMTA0NCwianRpIjoidndLWHlOYlJmTXdzMlFZbCIsInN1YiI6MiwicHJ2IjoiODdlMGFmMWVmOWZkMTU4MTJmZGVjOTcxNTNhMTRlMGIwNDc1NDZhYSJ9.Tr_CTZeKX6M2pycRal7CGeQ0i3FA3Fco0Xm5dwtWwDA",
"user": {
"id": 2,
"name": "hani",
Set and get
if (res.statusCode == 200) {
setState(() {
message = "Login Success";
});
print(res.body);
SharedPreferences localStorage = await SharedPreferences.getInstance();
localStorage.setString('user', json.encode(body['result']['user']));
String name;
_loadUserData() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var user = jsonDecode(localStorage.getString('user'));
if (user != null) {
setState(() {
name = user['name'];
});
}
}
But if i want to get the id from this API Response, what should i write?
to set and get that id using SharedPreferences.
Or there's another way to get that id?
"status": "success",
"result": [
{
"id": 1,
"exercise_name": "Reading Set 1",
"exercise_type_id": 1,
"show": 1,
"finalized": 1,
"created_at": "2021-12-17T07:13:50.000000Z",
"updated_at": "2021-12-17T20:47:57.000000Z",
"total": 0
},
{
"id": 3,
"exercise_name": "Reading Set 2",
"exercise_type_id": 1,
"show": 1,
"finalized": 1,
"created_at": "2021-12-17T20:34:50.000000Z",
"updated_at": "2021-12-17T20:46:15.000000Z",
"total": 0
}
]
Sorry, I new to coding and flutter.
Hope someone can help
In the first response result is a JSONObject but in the second one it is JSONArray.
if (res.statusCode == 200) {
//do what ever you want
final data = jsonDecode(response.body) as Map<String, dynamic>;
for (var exercise in data['result']) {
//Now you can access each item
if(exercise['exercise_name']== 'Reading Set 1'){
//Store ID in SharedPrefrence
}
}
}

Flutter Amplify Cognito, no tokens using fetchAuthSession

I'm trying to implement authentication in my Flutter app using Cognito. I'm authenticating against an existing userPool which I've been successfully using for the past year in my React app.
However, with Flutter I'm not able to fetch the user's session. I'm able to login successfully but I'm unable to get any tokens using the fetchAuthSession() method. Any idea why this is happening? Here is some of my working and non-working code:
This code is successful...
Future _usersEmail() async {
try {
var attributes = (await Amplify.Auth.fetchUserAttributes()).toList();
for (var attribute in attributes) {
if (attribute.userAttributeKey == 'email') {
print("user's email is ${attribute.value}");
return '${attribute.value}';
}
}
return 'no email';
} on AuthException catch (e) {
return '${e.message}';
}
}
This code is successful too...
Future<bool> _isSignedIn() async {
final CognitoAuthSession session =
await Amplify.Auth.fetchAuthSession() as CognitoAuthSession;
print('_isSignedIn: ${session.isSignedIn}');
return session.isSignedIn;
}
This code return null...
Future _getIdToken() async {
final CognitoAuthSession session =
await Amplify.Auth.fetchAuthSession() as CognitoAuthSession;
final idToken = session.userPoolTokens?.idToken;
print('idToken: $idToken');
return idToken;
}
Here is my amplifyconfig...
{
"UserAgent": "aws-amplify-cli/2.0",
"Version": "1.0",
"auth": {
"plugins": {
"awsCognitoAuthPlugin": {
"UserAgent": "aws-amplify-cli/0.1.0",
"Version": "0.1.0",
"IdentityManager": {
"Default": {}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "us-east-1_abcxyz",
"Region": "us-east-1"
}
}
},
"CognitoUserPool": {
"Default": {
"PoolId": "us-east-1_abcxyz",
"AppClientId": "5j0kii90dJ09est43xh3X21",
"Region": "us-east-1"
}
},
"Auth": {
"Default": {
"authenticationFlowType": "USER_SRP_AUTH"
}
}
}
}
}
}
you might need to set getAWSCredentials to true in your options parameter like so:
final authSession = (await Amplify.Auth.fetchAuthSession(
options: CognitoSessionOptions(getAWSCredentials: true),
)) as CognitoAuthSession;

Flutter return array from response from server

in this part of my code await webApi.getKeywords(); return array which that can get from server, now when i try to return that i get error:
type 'List<dynamic>' is not a subtype of type 'String'
get data from server code:
Future<List<KeywordsResponse>> _getKeywords(BuildContext context) async {
try {
final webApi = Provider.of<WebApi>(context);
final response = await webApi.getKeywords();
List<KeywordsResponse> list = List();
if (response.statusCode == 200) {
list = (json.decode(response.body) as List)
.map((data) => new KeywordsResponse.fromJson(data))
.toList();
return list;
} else {
throw Exception('Failed to load photos');
}
} catch (error) {
print(error);
return null;
}
}
KeywordsResponse class:
#JsonSerializable(nullable: true)
class KeywordsResponse{
#JsonKey(name:'id')
final int id;
#JsonKey(name:'title')
final String title;
#JsonKey(name:'description')
final String description;
KeywordsResponse(this.id, this.title, this.description);
factory KeywordsResponse.fromJson(Map<String, dynamic> json) => _$KeywordsResponseFromJson(json);
Map<String, dynamic> toJson() => _$KeywordsResponseToJson(this);
}
return of response.body:
[
{
"id": 1,
"user_id": 1,
"title": "asdasdasd",
"description": "asdasdasd",
"type": "post",
"slug": "asdasdad",
"featured_images": {
"images": {
"300": "/uploads/post_images/2019/300_1573573784.png",
"600": "/uploads/post_images/2019/600_1573573784.png",
"900": "/uploads/post_images/2019/900_1573573784.png",
"original": "/uploads/post_images/2019/1573573784.png"
},
"thumbnail": "/uploads/post_images/2019/300_1573573784.png"
},
"lang": "fa",
"visit": 0,
"categories": [
{
"id": 1,
"title": "aaaaaaa",
"lang": "fa",
"parent": 0,
"pivot": {
"contents_id": 1,
"content_categories_id": 1
}
}
]
},
{
"id": 2,
"user_id": 1,
"title": "asdasdasd",
"description": "asdadasd",
"type": "post",
"slug": "asdasdasda",
"featured_images": {
"images": {
"300": "/uploads/post_images/2019/300_1573573846.png",
"600": "/uploads/post_images/2019/600_1573573846.png",
"900": "/uploads/post_images/2019/900_1573573846.png",
"original": "/uploads/post_images/2019/1573573846.png"
},
"thumbnail": "/uploads/post_images/2019/300_1573573846.png"
},
"lang": "fa",
"visit": 0,
"categories": [
{
"id": 2,
"title": "bbbbbbbb",
"lang": "fa",
"parent": 0,
"pivot": {
"contents_id": 2,
"content_categories_id": 2
}
}
]
}
]
problem is on this line of code:
json.decode(response.body)
Try this:
list = List<KeywordsResponse>.from(response.body.map((x) => KeywordsResponse.fromJson(x)));