skip to Main Content

I am new to Flutter and currently working on a project where I need to validate an API key entered by the user in a TextFormField. The validation process involves making an HTTP request and checking the response code. If the response code is 200, the API key is considered valid; otherwise, it is considered invalid.

Here’s the relevant code snippet I have so far:
Code for validate API

Future<bool> validateAPI(String apiKey) async {
  if (apiKey.isEmpty) {
    return false;
  }
  final url = Uri.parse('https://api.openai.com/v1/usage');

  final response = await http.get(
    url,
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer $apiKey',
    },
  );
  
  if (response.statusCode == 200) {
    return true;
  }
  
  return false;
}

Code for TextFormField:

TextFormField(
  controller: _apiController,
  obscureText: hidden,
  validator: (value) async {
    if (value!.isEmpty) {
      return "API Key is required";
    } else {
      if (await validateAPI(value)) { // Issue: Error in type casting
        return null;
      } else {
        return "API Key is not valid";
      }
    }
  },
  enableSuggestions: false,
  decoration: InputDecoration(
    contentPadding: const EdgeInsets.only(right: 40),
    label: "API Key".text.make(),
    hintStyle: TextStyle(color: context.theme.hintColor)
  ),
),

However, I’m encountering an error when trying to cast the result of validateAPI(value) to a bool using await. The error message states:

"Unhandled Exception: type ‘Future<bool>’ is not a subtype of type ‘bool’ in type cast".

I would appreciate any guidance on how to properly handle this validation step in Flutter.

I attempted to cast the result of the validateAPI(value) function to a bool using await, expecting it to return true or false based on the validation result. Specifically, I used the following code:

if (await validateAPI(value)) {
  return null;
} else {
  return "API Key is not valid";
}

I expected the validation function to return a bool value indicating whether the API key is valid or not. If it is valid, I wanted to return null to indicate no validation error. Otherwise, I wanted to return the error message "API Key is not valid". However, instead of getting the expected behavior, I encountered the following error:

"Unhandled Exception: type ‘Future<bool>’ is not a subtype of type ‘bool’ in type cast"

This error indicates that the type casting from Future to bool is incorrect. I’m seeking guidance on how to properly handle the validation step and resolve this issue. Any assistance would be greatly appreciated.

2

Answers


  1. ‘Future<String?> Function(String?)’ can’t be assigned to the parameter type ‘String? Function(String?)?

    its beacause the validator doesn’t accept future type

    you can call your function when user does certain action.
    Also don’t forget to wrap your api call with try/catch block.

    import 'package:flutter/material.dart';
    import 'package:http/http.dart';
    
    void main() => runApp(const MyApp());
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
      static const String _title = 'Flutter ';
     
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: _title,
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key});
      
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      final _apiController = TextEditingController();
      final key = GlobalKey<FormState>();
      String? errorText;
      Future<void> buttonPressed() async {
        final value = key.currentState?.validate();
        if (value != null && value) {
          await validatorTree(_apiController.text.toString());
        }
      }
    
      Future<bool> validateAPI(String apiKey) async {
        if (apiKey.isEmpty) {
          return false;
        }
        final url = Uri.parse('https://api.openai.com/v1/usage');
    
        final response = await http.get(
          url,
          headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer $apiKey',
          },
        );
    
        if (response.statusCode == 200) {
          return true;
        }
    
        return false;
      }
    
      Future<void> validatorTree(String value) async {
        try {
          final response = await validateAPI(value);
          if (response) {
            errorText=null;
          } else {
            errorText= "failure";
          }
        } catch (e) {
          print(e);
          errorText= "failure";
        }
        setState(() {
          
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Flutter Demo '),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Form(
                  key: key,
                  child: TextFormField(
                    controller: _apiController,
                    obscureText: false,
                    
                    validator: (value) {
                      if (value!.isEmpty) {
                        return "API Key is required";
                      }
                      return null;
                    },
                    
                    enableSuggestions: false,
                    decoration:  InputDecoration(
                      errorText: errorText,
                      contentPadding: const EdgeInsets.only(right: 40),
                    ),
                  ),
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: buttonPressed,
            tooltip: 'button',
            child: const Icon(Icons.account_circle),
          ),
        );
      }
    }
    
    Login or Signup to reply.
  2. The error is cause the validator doesn’t accept the Future type.

    I had the same requirement in my application so i used this method to validate the TextField, you need to take a formKey and a bool for the invalid api key state.

    final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
    bool _isKeyInValid = false;
    

    Now wrap the TextField in the Form widget and pass the _formKey to the Form.

    Form(
        key: _formKey,
        child: TextFormField(
          controller: _apiController,
          obscureText: hidden,
          validator: (value) {
            if (value!.isEmpty) {
              return "API Key is required";
            } else if (_isKeyInValid) {
              return "API Key is not valid";
            } else {
              return null;
            }
          },
          onFieldSubmitted: validateAPI,  // <- validating the key on field submit.
          enableSuggestions: false,
          decoration: InputDecoration(
              contentPadding: const EdgeInsets.only(right: 40),
              label: "API Key".text.make(),
              hintStyle: TextStyle(color: context.theme.hintColor)),
        ),
      ),
    

    Currently i’m making the validateApi function call on the TextField submit you can call it from any-other widget, like button click…
    And i have added a else if in the validator as isKeyInaValid is true you will get an "API Key is not valid" message.

    Future validateAPI(String apiKey) async {
    if (apiKey.isEmpty) {
      return false;
    }
    final url = Uri.parse('https://api.openai.com/v1/usage');
    final response = await http.get(
      url,
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer $apiKey',
      },
    );
    if (response.statusCode == 200) {
      /// valid key
      // return true;
    } else {
      /// invalid key
    
      _isKeyInValid = true;
      _formKey.currentState?.validate();
    
      // return false;
    }
    }
    

    Now the function, if the key is invalid then we set the isKeyInValid bool to true then validate the form, so the TextField will validated and as the isKeyInValid is true you will get you desired error message.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search