簡體   English   中英

如何在flutter中向graphql API發送post請求

[英]How to send post request to graphql API in flutter

我正在嘗試通過開發一個簡單的應用程序來學習如何將 rails 與 graphql 結合使用來創建一個 rails API,該應用程序只從數據庫中檢索文本(在我的例子中是引號)並將其顯示在屏幕上。 我在前端和 rails 中使用 flutter,以 graphql 作為后端。 后端部分很容易創建,因為我已經掌握了一些 Rails 知識,但前端部分是我的新手,我正在嘗試弄清楚如何訪問我通過 flutter 創建的 graphql 查詢以獲取需要的數據要顯示。

下面是我目前擁有的 flutter 代碼(部分改編自How to build a mobile app from scratch with Flutter and may Rails? )。

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<Quote> fetchQuote() async {
  final response =
      await http.get('http://10.0.2.2:3000/graphql?query={quote{text}}');

  if (response.statusCode == 200) {
    // If the call to the server was successful, parse the JSON.
    return Quote.fromJson(json.decode(response.body));
  } else {
    // If that call was not successful, throw an error.
    throw Exception('Failed to load quote');
  }
}

class Quote {
  final String text;

  Quote({this.text});

  factory Quote.fromJson(Map<String, dynamic> json) {
    return Quote(
      text: json['text']
    );
  }
}


void main() => runApp(MyApp(quote: fetchQuote()));

class MyApp extends StatelessWidget {
  final Future<Quote> quote;

  MyApp({this.quote});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fetch Data Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Fetch Data Example'),
        ),
        body: Center(
          child: FutureBuilder<Quote>(
            future: quote,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Text(snapshot.data.text);
              } else if (snapshot.hasError) {
                return Text("${snapshot.error}");
              }

              // By default, show a loading spinner.
              return CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}

這段代碼錯誤的一些顯而易見的原因是我自己已經發現,graphql 服務器期望在我的代碼發送 get 請求時對查詢進行 post 請求,但這是我的問題。 如何在flutter中為我的graphql服務器發送post請求以檢索數據? 我試圖訪問的查詢是我的顫振代碼中 '?query=' 之后的查詢。

這也花了我一分鍾的時間來弄清楚,但這是我在練習待辦事項應用程序中所做的:

1 -通過 http閱讀有關 graphql 發布請求的頁面 有一個部分用於GET請求以及POST

2 -確保你的body函數參數是正確的 json 編碼(見下面的代碼)。

提示:使用 Postman,您可以測試具有不同標頭和授權令牌以及請求正文的 graphql 端點。 它還具有從請求生成代碼的簡潔功能。 查看此頁面了解詳細信息 這不是 100% 准確,但這幫助我弄清楚如何正確設置請求正文的格式。 在函數post ,如果您提供 Map 作為請求的主體(並且請求內容類型是application/json ),顯然您無法更改內容類型,因此 String 適合我的用例。

示例代碼(使用GqlParser類對請求正文進行正確編碼):

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'todo.dart';
import '../creds/creds.dart';
import 'gql_parser.dart';

const parser = GqlParser('bin/graphql');

class TodoApiException implements Exception {
  const TodoApiException(this.message);
  final String message;
}

class TodoApiClient {
  const TodoApiClient();
  static final gqlUrl = Uri.parse(Credential.gqlEndpoint);
  static final headers = {
    "x-hasura-admin-secret": Credential.gqlAdminSecret,
    "Content-Type": "application/json",
  };

  Future<List<Todo>> getTodoList(int userId) async {
    final response = await http.post(
      gqlUrl,
      headers: headers,
      body: parser.gqlRequestBody('users_todos', {'userId': userId}),
    );

    if (response.statusCode != 200) {
      throw TodoApiException('Error fetching todos for User ID $userId');
    }

    final decodedJson = jsonDecode(response.body)['data']['todos'] as List;
    var todos = <Todo>[];

    decodedJson.forEach((todo) => todos.add(Todo.fromJson(todo)));
    return todos;
  }
// ... rest of class code ommitted

根據.post()正文參數文檔:

如果是字符串,則使用 [encoding] 對其進行編碼並用作請求的正文。 請求的內容類型將默認為“text/plain”。

如果 [body] 是一個列表,則它被用作請求正文的字節列表。

如果 [body] 是 Map,則使用 [encoding] 將其編碼為表單字段。 請求的內容類型將設置為“application/x-www-form-urlencoded”; 這不能被覆蓋。

我在GqlParser類中使用以下代碼簡化了字符串的創建以作為參數的主體提供。 這將讓你有一個文件夾,例如graphql包含多個*.graphql查詢/突變。 然后,您只需在需要進行簡單 graphql 端點請求的其他類中使用parser ,並提供文件名(不帶擴展名)。

import 'dart:convert';
import 'dart:io';

class GqlParser {
  /// provide the path relative to of the folder containing graphql queries, with no trailing or leading "/".
  /// For example, if entire project is inside the `my_app` folder, and graphql queries are inside `bin/graphql`,
  /// use `bin/graphql` as the argument.
  const GqlParser(this.gqlFolderPath);

  final String gqlFolderPath;

  /// Provided the name of the file w/out extension, will return a string of the file contents
  String gqlToString(String fileName) {
    final pathToFile =
        '${Directory.current.path}/${gqlFolderPath}/${fileName}.graphql';
    final gqlFileText = File(pathToFile).readAsLinesSync().join();
    return gqlFileText;
  }

  /// Return a json-encoded string of the request body for a graphql request, given the filename (without extension)
  String gqlRequestBody(String gqlFileName, Map<String, dynamic> variables) {
    final body = {
      "query": this.gqlToString(gqlFileName),
      "variables": variables
    };
    return jsonEncode(body);
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM