So im trying to implement graphql in flutter, using bloc too. I think i already did all the necessary part, but when i try to hit the graphql, it return response like this
HttpLinkParserException (ResponseFormatException(originalException: FormatException: Unexpected character (at character 1)
here is my graphql function –
void _onLoginButtonPressed(
LoginButtonPressed event, Emitter<LoginState> emit) async {
emit(LoginLoading());
try {
// Define your login mutation
final String loginMutation = '''
mutation Login($uname: String!, $pass: String!, $idNum: String!, $deviceId: String!) {
login(uname: $uname, pass: $pass, idNum: $idNum, deviceId: $deviceId) {
accessToken
refreshToken
}
}
''';
// Define variables for your mutation
final Map<String, dynamic> variables = {
'uname': event.username,
'pass': event.password,
'idNum': event.idNum,
'deviceId': event.deviceId,
};
// Execute the login mutation and get the response
final QueryResult result = await graphQLClient.mutate(
MutationOptions(
document: gql(loginMutation),
variables: variables,
),
);
if (result.hasException) {
print(result.exception!);
} else {
// Extract access token and refresh token from the response
final accessToken = result.data?['login']['accessToken'];
final refreshToken = result.data?['login']['refreshToken'];
emit(
LoginSuccess(accessToken: accessToken, refreshToken: refreshToken));
}
} catch (e) {
emit(LoginFailure(error: e.toString()));
}
}
this is the response when I try using postman
{
"data": {
"login": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVbmFtZSI6ImRlbyIsIlJlZ2lzdGVyZWRDbGFpbXMiOnsiaXNzIjoiYnJtb2JpbGUiLCJleHAiOjE2OTY5MDkwNTZ9fQ.XT57BIVfR6Ct8IIf5zHicqhwIqF_J9Ckj9FWflzQdwc",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVbmFtZSI6ImRlbyIsIlJlZ2lzdGVyZWRDbGFpbXMiOnsiaXNzIjoiYnJtb2JpbGUiLCJleHAiOjE2OTY5MjM0NTZ9fQ.MTBtgeKe9cgrPE4CnCPG7Z4vagi9_7qm4PDT4aJ6Nbo"
}
}
}
this is my graphql setup, on the main file:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initializes Hive with a valid directory in your app files
await Hive.initFlutter();
await Hive.openBox("userBox");
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GraphQLClient client = GraphQLClient(
link: HttpLink('http://127.0.0.1:7130/graphql/'),
cache: GraphQLCache(),
);
final AuthLink authLink = AuthLink(
getToken: () async {
final box = Hive.box('userBox');
final token = box.get('accessToken');
return 'Bearer $token';
},
);
late final ValueNotifier<GraphQLClient> clientNotifier =
ValueNotifier<GraphQLClient>(client);
@override
Widget build(BuildContext context) {
return GraphQLProvider(
client: clientNotifier,
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
routes: {
'/home': (context) => const Scaffold(
body: Center(
child: Text('Home'),
),
),
},
home: BlocProvider(
create: (context) => LoginBloc(graphQLClient: client),
child: LoginScreen(),
),
),
);
}
}
This is my widget where I use the bloc
class _LoginScreenState extends State<LoginScreen> {
TextEditingController usernameController = TextEditingController();
TextEditingController passwordController = TextEditingController();
TextEditingController idNumController = TextEditingController();
TextEditingController deviceIDController = TextEditingController();
@override
Widget build(BuildContext context) {
final loginBloc = BlocProvider.of<LoginBloc>(context);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Login'),
),
body: Center(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: BlocBuilder<LoginBloc, LoginState>(
builder: (context, state) {
if (state is LoginLoading) {
return const CircularProgressIndicator();
} else if (state is LoginSuccess) {
print('object');
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) =>
HomeScreen()), // Replace with your desired screen
);
} else if (state is LoginFailure) {
return Text('Login Failed: ${state.error}');
}
return Container(
child: Column(
children: [
TextField(
controller: usernameController,
decoration: const InputDecoration(
labelText: 'Username',
),
),
TextField(
controller: passwordController,
decoration: const InputDecoration(
labelText: 'Password',
),
),
TextField(
controller: idNumController,
decoration: const InputDecoration(
labelText: 'IdNum',
),
),
TextField(
controller: deviceIDController,
decoration: const InputDecoration(
labelText: 'DeviceId',
),
),
ElevatedButton(
onPressed: () {
final username = usernameController.text;
final password = passwordController.text;
final deviceId = deviceIDController.text;
final idNum = idNumController.text;
loginBloc.add(LoginButtonPressed(
username: username,
password: password,
idNum: idNum,
deviceId: deviceId,
));
Navigator.pop(context);
},
child: const Text('Login'),
),
],
),
);
},
),
)
],
),
),
);
}
}
2
Answers
Below is a solution (you might need to fix some imports) where the build is being forced to wait for the graphclient to be created.
Seems u need to concat the auth Link and httpLink and then fed to the GraphQlClient. Hope tht helps for u