HTTP请求的Singleton类

时间:2019-06-19 05:08:38

标签: flutter

您能提供一些建议,如何为Flutter中的api请求设计类吗?我是ios开发人员,我在alamofire中使用了单例类。如果您提供一些代码,那就太好了!

class Client: ApiBase {
    static let shared = Client()
    private override init() {}

    func login(phoneNumber: String, password: String, completion: @escaping(_ error: String?) -> Void) {
        let params: [String : String] = [
            "userId" : phoneNumber,
            "password" : password,
        ]

        baseRequest(route: ApiRouter.login(), params: params) { (response) in
            if let json = response.json {
                Session.current.sessionId = json["sessionId"].string
            }

            completion(response.error)
        }
    }
}

登录方法的调用方式:

@IBAction func singin(_ sender: TransitionButton) {
    Client.shared.login(phoneNumber: "12312", password: "123") { (error) in
        guard error == nil else {
            // show error
            return
        }

        // navigate to home page
    }
}

2 个答案:

答案 0 :(得分:0)

在扑朔迷离中,您不必处理IBAction的相对麻烦,将协议作为回调或保留周期,而您需要asyncawait来提供帮助。

有几种方法可以进行API调用-一种是将它们简单地放在与UI相同的代码中。这有缺点,但肯定可以理解。



class WhateverMyComponentIsState extends State<WateverMyComponentIs> {

  Future<String> _doLogin({@required String phoneNumber, @required String password}) async {
    final response = await http.post(LOGIN_URL, body: {'userId': phoneNumber, 'password': password})
    if (response.statusCode == 200) {
      final jsonResponse = jsonDecode(body);
      return jsonResponse['sessionId'];
    } else {
      ... error handling

    }

  }

  String phoneNumber;
  String password; 

  @override
  Widget build(BuildContext context) {
    return ...(
      child: FlatButton(
        onPressed: () async {
          final sessionId = await _doLogin(phoneNumber: phoneNumber, password: password);

          ... do whatever - setState(() => loggedIn = true), or Navigator.push ...
        }
      ),
     )
  }
} 

如果需要,您可以将所有api调用提取到另一个类中-它们可以是静态方法,但这使它变得更加难以编写良好的测试(如果您决定这样做)。

我个人的建议是使用一种或多或少的“依赖注入”形式,方法是利用InheritedWidget提供一个类的实现,该类实际执行登录(并且可以保存sessionId)。不过,您可以使用我个人非常喜欢的ScopedModel plugin,而不是自己实现所有这些,因为它可以大大减少所需的样板数量。

如果您正确地使用了ScopedModel(我将在练习中留给我-我很确定还有其他问题),则可以使用它或它提供的类来执行http请求,然后sessionId存储在ScopedModel中。

这样做的好处是,如果您要开始编写测试(或不得不处理两个服务器等),则可以用实现相同接口但不使用相同接口的另一个ScopedModel替换ScopedModel。实际执行http请求或以不同的方式执行它们。

答案 1 :(得分:0)

在混乱中,您应该创建一个类似这样的类

class User {
  String name;
  String pass;


  User({
      this.name,
      this.pass,
      });

  User.fromJson(Map<String, dynamic> json) {
    name = json['name'];
    pass= json['pass'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['name'] = this.name;
    data['pass'] = this.pass;
    return data;
  }
}

现在创建类似这样的User类类型的列表

final List<User> user;
  

现在调用用户身份验证的URL(API)

 Future<void> validateUsr() async {
    var client = new http.Client();


    try {
      var response = await client.get(
          'https://xxxxxxxx/wp-json/jwt-auth/v1/token?username=xxxxx2&password=xxxxxx');
      if (response.statusCode == 200) {
        var data = json.decode(response.body);
        var list = data as List;
        setState(() {
         user=list.map<User>((i) => User.fromJson(i)).toList();

        });
      } else {
        print('Somthing went wrong');
      }
    } catch (e) {
      print(e);
    } finally {
      client.close();
    }
  }

希望这对您有帮助