This article will walk you through creating a Flutter project and plugging into GraphQL.

Project depend on

  • Flutter Development Environment – See How to Install Flutter
  • Code editor for the Flutter plugin installed – see Configuration Editor
  • A GraphQL backend running – see building a GraphQL Backend Project in 10 Minutes
  • LAN IP on the backend of GraphQL – See “How to View LAN IP address on the Command Line”

Create a project

Create a brand new Flutter project tinyLearn_client:

$ flutter create tinylearn_client
Copy the code

Use the code editor to open the project:

Click on the file lib/main.dart, clean up the code, remove the comment and change it to:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page')); }}class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    returnScaffold( appBar: AppBar( title: Text(widget.title), ), body: Container(), ); }}Copy the code

After running, we get:

Access to theGraphQL

Install the dependency library Graphql_flutter:

pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
+ graphql_flutter: ^ 3.0.1
Copy the code

Run:

$ flutter pub get
Copy the code

With that in mind, let’s review what we learned in the previous episode “Building a GraphQL Back-end Project in 10 Minutes” :

This is the “Postman” page we mentioned in the last video. In the middle of the image is the JSON returned by the server. Let’s first parse the JSON.

You can parse JSON any way you like. Here I use the online tool QuickType to generate the Model. See How to Convert JSON to Model using the Online Transcoding Tool Flutter.

Save the parsing code in a new file lib/ postsdata.dart:

// To parse this JSON data, do
//
// final postsData = postsDataFromJson(jsonString);

import 'dart:convert';

class PostsData {
    final List<Post> posts;

    PostsData({
        this.posts,
    });

    factory PostsData.fromJson(String str) => PostsData.fromMap(json.decode(str));

    String toJson() => json.encode(toMap());

    factory PostsData.fromMap(Map<String.dynamic> json) => PostsData(
        posts: json["posts"] = =null ? null : List<Post>.from(json["posts"].map((x) => Post.fromMap(x))),
    );

    Map<String.dynamic> toMap() => {
        "posts": posts == null ? null : List<dynamic>.from(posts.map((x) => x.toMap())),
    };
}

class Post {
    final String id;
    final int created;
    final String content;

    Post({
        this.id,
        this.created,
        this.content,
    });

    factory Post.fromJson(String str) => Post.fromMap(json.decode(str));

    String toJson() => json.encode(toMap());

    factory Post.fromMap(Map<String.dynamic> json) => Post(
        id: json["id"] = =null ? null : json["id"],
        created: json["created"] = =null ? null : json["created"],
        content: json["content"] = =null ? null : json["content"]);Map<String.dynamic> toMap() => {
        "id": id == null ? null : id,
        "created": created == null ? null : created,
        "content": content == null ? null : content,
    };
}
Copy the code

Dart = lib/main.dart = lib/main.dart

import 'package:flutter/material.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:tinylearn_client/PostsData.dart'; .final _uri = 'http://10.0.0.10:4444/';  // The IP address is the LAN IP address of the server, and the port number is 4444. You need to configure it according to the network environment

class _MyHomePageState extends State<MyHomePage> {

  Future<PostsData> _postsData;

  @override
  void initState() {
    
    final client = GraphQLClient(
      cache: InMemoryCache(),
      link: HttpLink(uri: _uri)
    );

    _postsData = _createPostsData(client);
    super.initState();
  }

  Future<PostsData> _createPostsData(GraphQLClient client) async {
        
    final result = await client.query(QueryOptions(
      documentNode: gql(r''' query { posts { id created content } } ''')));if (result.hasException) throw result.exception;
    returnPostsData.fromMap(result.data); }... }Copy the code

First, configure a GraphQLClient that lets you send requests to the GraphQL server.

final _uri = 'http://10.0.0.10:4444/'; 

class _MyHomePageState extends State<MyHomePage> {...@override
  void initState() {
    
    finalclient = GraphQLClient( cache: InMemoryCache(), link: HttpLink(uri: _uri) ); . }... }Copy the code

Note that final _uri = ‘http://10.0.0.10:4444/’; Is the address of the GraphQL server. Using the backend written in the previous article “Building a GraphQL Backend Project in 10 Minutes”, we need to configure it as the BACKEND LAN IP and port number: http://${backendLanIP}:4444/

BackendLanIP may be 192.169.0.10 or 10.0.0.10, which you need to query yourself.

Let’s define a method Future _createPostsData(GraphQLClient client) that uses the client to request PostsData data from the GraphQL server:

.class _MyHomePageState extends State<MyHomePage> {

  Future<PostsData> _postsData;

  @override
  void initState() {
    
    finalclient = ... ; _postsData = _createPostsData(client);super.initState();
  }

  Future<PostsData> _createPostsData(GraphQLClient client) async {
        
    final result = await client.query(QueryOptions(
      documentNode: gql(r''' query { posts { id created content } } ''')));if (result.hasException) throw result.exception;
    returnPostsData.fromMap(result.data); }... }Copy the code

The requested parameters are from the configuration to the left of “Postmain”.

Next, we draw the page, which will consume the request and display the results as a list:

. Future<PostsData> _createPostsData(GraphQLClient client)async{... }@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: FutureBuilder<PostsData>(
          future: _postsData,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              final List<Post> posts = snapshot.data.posts;
              return _buildListView(posts);
            }
            if (snapshot.hasError) {
              return Text('${snapshot.error}', textAlign: TextAlign.center);
            }
            returnCircularProgressIndicator(); },),),); } ListView _buildListView(List<Post> posts) {
    return ListView.separated(
      itemCount: posts.length,
      itemBuilder: (context, index) {
        final post = posts[index];
        return _postListTile(post);
      },
      separatorBuilder: (context, index) => Divider(),
    );
  }

  ListTile _postListTile(Post post) {
    returnListTile( title: Text(post.content), subtitle: Text(post.created.time.toString()), ); }...Copy the code

Finally, add an extension method to convert the int timestamp returned by the server to DateTime.

.class MyHomePage extends StatefulWidget {... } extension Time onint {

  DateTime get time => DateTime.fromMillisecondsSinceEpoch(this);
}
Copy the code

Run:

And you’re done!

To be continued

This time we got through the front and back ends of GraphQL and demonstrated some basic functionality. The next article, When to Use GraphQL? We’ll start with the design philosophy of GraphQL, its strengths and weaknesses. Later, we will put these concepts into action and create a fully functional front and back end product.

If you have any ideas, please leave me a message.

Source:

The code address

lib/main.dart:

import 'package:flutter/material.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:tinylearn_client/PostsData.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page')); }}class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

final _uri = 'http://10.0.0.105:4444/';

class _MyHomePageState extends State<MyHomePage> {

  Future<PostsData> _postsData;

  @override
  void initState() {

    final client = GraphQLClient(
      cache: InMemoryCache(),
      link: HttpLink(uri: _uri)
    );

    _postsData = _createPostsData(client);
    super.initState();
  }

  Future<PostsData> _createPostsData(GraphQLClient client) async {
        
    final result = await client.query(QueryOptions(
      documentNode: gql(r''' query { posts { id created content } } ''')));if (result.hasException) throw result.exception;
    return PostsData.fromMap(result.data);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: FutureBuilder<PostsData>(
          future: _postsData,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              final List<Post> posts = snapshot.data.posts;
              return _buildListView(posts);
            }
            if (snapshot.hasError) {
              return Text('${snapshot.error}', textAlign: TextAlign.center);
            }
            returnCircularProgressIndicator(); },),),); } ListView _buildListView(List<Post> posts) {
    return ListView.separated(
      itemCount: posts.length,
      itemBuilder: (context, index) {
        final post = posts[index];
        return _postListTile(post);
      },
      separatorBuilder: (context, index) => Divider(),
    );
  }

  ListTile _postListTile(Post post) {
    return ListTile(
      title: Text(post.content),
      subtitle: Text(post.created.time.toString()),
    );
  }
}

extension Time on int {

  DateTime get time => DateTime.fromMillisecondsSinceEpoch(this);
}
Copy the code

lib/PostData.dart:

// To parse this JSON data, do
//
// final postsData = postsDataFromJson(jsonString);

import 'dart:convert';

class PostsData {
    final List<Post> posts;

    PostsData({
        this.posts,
    });

    factory PostsData.fromJson(String str) => PostsData.fromMap(json.decode(str));

    String toJson() => json.encode(toMap());

    factory PostsData.fromMap(Map<String.dynamic> json) => PostsData(
        posts: json["posts"] = =null ? null : List<Post>.from(json["posts"].map((x) => Post.fromMap(x))),
    );

    Map<String.dynamic> toMap() => {
        "posts": posts == null ? null : List<dynamic>.from(posts.map((x) => x.toMap())),
    };
}

class Post {
    final String id;
    final int created;
    final String content;

    Post({
        this.id,
        this.created,
        this.content,
    });

    factory Post.fromJson(String str) => Post.fromMap(json.decode(str));

    String toJson() => json.encode(toMap());

    factory Post.fromMap(Map<String.dynamic> json) => Post(
        id: json["id"] = =null ? null : json["id"],
        created: json["created"] = =null ? null : json["created"],
        content: json["content"] = =null ? null : json["content"]);Map<String.dynamic> toMap() => {
        "id": id == null ? null : id,
        "created": created == null ? null : created,
        "content": content == null ? null : content,
    };
}
Copy the code

reference

  • Flutter
  • GraphQL