Redis
 Computer >> コンピューター >  >> プログラミング >> Redis

Flutter、サーバーレスフレームワーク、Upstash(REDIS)を備えたフルスタックサーバーレスアプリ-パート2

このチュートリアルシリーズのパート2へようこそ。最初のパートでは、Upstash、Serverless Framework、およびRedisを使用してRESTAPIを構築する方法を説明しました。

このパートでは、Flutterを使用してモバイルアプリケーションを構築し、RESTAPIエンドポイントを使用します。

始めましょう🙃

まず、フラッターをコンピューターにインストールして実行する必要があります

  • フラッター

IDEで新しいフラッタープロジェクトを作成し、任意の名前を付けます。

pubspec.yamlを開きます flutterプロジェクトのルートディレクトリにあるファイルを作成し、これらの依存関係をdev_dependenciesの下に追加します

timeago: ^3.1.0
shared_preferences: ^2.0.6
http: ^0.13.4

したがって、最終的には次のようになります

dev_dependencies:
  flutter_test:
    sdk: flutter

  timeago: ^3.1.0
  shared_preferences: ^2.0.6
  http: ^0.13.4

timeago ライブラリは、Unixタイムスタンプ(1636824843)をa minute agoのような人間が読める形式に変換しています 、 5 mins ago など

Once we create a user account, we want to keep track of their userIdand other minor details. We'll use そのためのshared_preferencesfor that. Then we'll use theを使用します HTTP呼び出しを行うためのhttp`ライブラリ。

始めましょう...

ユーザーの作成

構築する最初の画面は、ユーザー作成エンドポイントを使用するユーザー作成画面です。

画面は次のようになります

Flutter、サーバーレスフレームワーク、Upstash(REDIS)を備えたフルスタックサーバーレスアプリ-パート2 バニーの写真について心配する必要はありません。 imageviewの単なるプレースホルダー。

lib内にフォルダを作成します accountというフォルダ 次に、create_profile_screen.dartという名前の新しいファイルを作成します account内 フォルダ。

これが私の最終的なlibの方法です フォルダ構造は次のようになります Flutter、サーバーレスフレームワーク、Upstash(REDIS)を備えたフルスタックサーバーレスアプリ-パート2 新しいユーザーを作成するには、

が必要です。
  • プロフィール写真のURL
  • 名前
  • ユーザー名
  • エンドポイント

コードを見てみましょう

static const String  CREATE_USER_PROFILE_URL = "https://5vafvrk8kj.execute-api.us-east-1.amazonaws.com/dev/user";
  bool _loading = false;

 Future<void>createUserProfile() async{
    setState(() {
      _loading = true;
    });
  print(usernameController.text);
  print(firstNameController.text);
  print(lastNameController.text);
  print(profilePicUrl);
    await http.post(Uri.parse(CREATE_USER_PROFILE_URL),
        body: convert.jsonEncode({'username': usernameController.text,
          "firstName":firstNameController.text,"lastName":lastNameController.text,
          "profilePic":profilePicUrl})).then((response) async {

      var jsonResponse =
      convert.jsonDecode(response.body) as Map<String, dynamic>;

      setState(() {
        _loading = false;
      });
      if(response.statusCode == 400){

       ScaffoldMessenger.of(context).showSnackBar(SnackBar(padding:EdgeInsets.all(10),backgroundColor: Colors.red,content: Text(jsonResponse['message'])));
      }else if(response.statusCode == 200) {

        print('user id is :' +jsonResponse['userId']);
        await saveUserId(jsonResponse['userId']);
        Navigator.push(context, MaterialPageRoute(builder: (context){
          return HomeScreen();
        }));
      }
    });



  }

Futureは、非同期操作を操作するためのコアDartクラスです。 Futureオブジェクトは、将来のある時点で利用可能になる可能性のある値またはエラーを表します。

http.Responseクラスには、成功したhttp呼び出しから受信したデータが含まれています。

上記のコードはhttp postを使用しています create user endpointにPOSTリクエストを送信するメソッド 次に、応答を待ちます。

応答ステータスコードが200の場合、リクエストは成功し、作成されたUserIdを共有設定に保存してから、ホーム画面に移動します。

この画面の完全なソースコードへのリンクは次のとおりです。プロファイルの作成画面。

投稿を作成

エンドポイントの1つにより、ユーザーは投稿を作成できました。画面は次のようになります

Flutter、サーバーレスフレームワーク、Upstash(REDIS)を備えたフルスタックサーバーレスアプリ-パート2

投稿を作成するには、ユーザーが必要です

  • userId
  • テキスト
  • imageUrl

デモンストレーションの目的で、既製のimageUrlを使用していることを忘れないでください。実際のアプリでは、ユーザーが画像を選択してサーバーにアップロードし、画像のURLを取得してから、それを使用して投稿を作成できるようにする必要があります。

CreatePost メソッドはCreateUserに似ています メソッド。

 Future<void> createPost(String userId) async {
    await http
        .post(Uri.parse(CREATE_USER_POST_URL),
            body: convert.jsonEncode({
              'userId': userId,
              "postText": postTextController.text,
              "postImage": _postPicUrl[i]
            }))
        .then((response) async {
      var jsonResponse =
          convert.jsonDecode(response.body) as Map<String, dynamic>;

      setState(() {
        _loading = false;
      });
      if (response.statusCode == 400) {
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
            padding: EdgeInsets.all(10),
            backgroundColor: Colors.red,
            content: Text(jsonResponse['message'])));
      } else if (response.statusCode == 200) {
        print('post id is :' + jsonResponse['id']);
        Navigator.of(context).pop();
      }
    });
  }

すべての投稿を一覧表示

アプリケーションのホーム画面には、作成されたすべての投稿のリストが表示されます。

このようなもの

Flutter、サーバーレスフレームワーク、Upstash(REDIS)を備えたフルスタックサーバーレスアプリ-パート2 ストレスのない方法ですべての投稿を取得するには、最初にカスタムダーツオブジェクトを作成する必要があります。単一の投稿を表します。

class Post {
  String? postText;
  String? userId;
  String? createdOn;
  String? id;
  String? postImage;
  PostAdmin? postAdmin;

  Post(
      {this.postText,
      this.userId,
      this.createdOn,
      this.id,
      this.postImage,
      this.postAdmin});

  Post.fromJson(Map<String, dynamic> json) {
    postText = json['postText'];
    userId = json['userId'];
    createdOn = json['createdOn'];
    id = json['id'];
    postImage = json['postImage'];
    postAdmin = json['postAdmin'] != null
        ? PostAdmin.fromJson(json['postAdmin'])
        : null;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['postText'] = this.postText;
    data['userId'] = this.userId;
    data['createdOn'] = this.createdOn;
    data['id'] = this.id;
    data['postImage'] = this.postImage;
    if (this.postAdmin != null) {
      data['postAdmin'] = this.postAdmin!.toJson();
    }
    return data;
  }
}

class PostAdmin {
  String? timestamp;
  String? userId;
  String? username;
  String? firstName;
  String? lastName;
  String? profilePic;

  PostAdmin(
      {this.timestamp,
      this.userId,
      this.username,
      this.firstName,
      this.lastName,
      this.profilePic});

  PostAdmin.fromJson(Map<String, dynamic> json) {
    timestamp = json['timestamp'];
    userId = json['userId'];
    username = json['username'];
    firstName = json['firstName'];
    lastName = json['lastName'];
    profilePic = json['profilePic'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['timestamp'] = this.timestamp;
    data['userId'] = this.userId;
    data['username'] = this.username;
    data['firstName'] = this.firstName;
    data['lastName'] = this.lastName;
    data['profilePic'] = this.profilePic;
    return data;
  }
}

次に、http.Responseを変換します そのカスタムDartオブジェクトに。

List<Post> parsePosts(String responseBody) {
  final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();

  return parsed.map<Post>((json) => Post.fromJson(json)).toList();
}

Future<List<Post>> fetchPosts(http.Client client) async {
  final response = await client
      .get(Uri.parse(GET_POSTS));

  return compute(parsePosts,response.body);
}

fetchPostsの戻りタイプ メソッドはFuture<List<Post>>です 。

低速のデバイスでfetchPosts()関数を実行すると、JSONを解析して変換するときに、アプリが一時的にフリーズすることに気付く場合があります。これはジャンクです、そしてあなたはそれを取り除きたいです。

computeを使用して解析と変換をバックグラウンドに移動することにより、ジャンクを削除します 関数

compute(parsePosts, response.body);

Compute()関数は、バックグラウンド分離で高価な関数を実行し、結果を返します

ホーム画面ファイルでは、FutureBuilderウィジェットを使用して、データベースからすべての投稿をリストとして非同期的に取得します。

2つのパラメータを提供する必要があります:

  • 一緒に働きたい未来。この場合、futureはfetchPosts()関数から返されます。

将来の状態(読み込み、成功、エラー)に応じて、Flutterに何をレンダリングするかを指示するビルダー関数。

snapshot.hasDataは、スナップショットにnull以外のデータ値が含まれている場合にのみtrueを返すことに注意してください。

fetchPostsはnull以外の値しか返すことができないため、「404 Not Found」サーバー応答の場合でも、関数は例外をスローする必要があります。例外をスローすると、snapshot.hasErrorがtrueに設定され、エラーメッセージの表示に使用できます。

それ以外の場合は、スピナーが表示されます。

Expanded(child: FutureBuilder<List<Post>>(
              future: _posts,
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  List<Post>? posts = snapshot.data;
                  if(posts != null){
                    return ListView.builder(itemBuilder: (context,index){
                      return  Card(
                        child: Container(
                          padding: EdgeInsets.all(10),
                          child: Row(
                           crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                          ClipRRect(
                          borderRadius: BorderRadius.circular(1000),
                          child: Image.network(
                            posts[index].postAdmin!.profilePic!,
                            fit: BoxFit.cover,
                            height: 40,
                            width: 40,
                          ),
                      ),
                          Expanded(
                            child: Container(
                              padding: EdgeInsets.only(left: 10),
                              child: Column(
                               mainAxisAlignment: MainAxisAlignment.start,
                               crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                              Text(posts[index].postAdmin!.username!,style: TextStyle(fontWeight: FontWeight.bold,fontSize: 16),),
                              Text(posts[index].postText!),
                                  ClipRRect(
                                    borderRadius: BorderRadius.circular(10),
                                    child: Image.network(
                                      posts[index].postImage!,
                                      fit: BoxFit.cover,
                                      height: 150,
                                      width: size.width,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          )
                            ],
                          ),
                        ),
                      );
                    },itemCount: posts.length,);
                  }

                } else if (snapshot.hasError) {
                  return Text("${snapshot.error}");
                }

                // By default, show a loading spinner.
                return Container(
                    height: 40,
                    width: 40,

                    child: Center(child: CircularProgressIndicator(valueColor: AlwaysStoppedAnimation<Color>(Theme.of(context).colorScheme.secondary))));
              },
            ))

initStateメソッドでは、fetchPosts

を呼び出します。
late Future<List<Post>> _posts;


  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _posts = fetchPosts(http.Client());

  }

buildメソッドの代わりにinitStateでfetchPostsを呼び出す理由は、ビュー内の何かを変更する必要があるたびにflutterがbuild()メソッドを呼び出すためです。これは、驚くほど頻繁に発生します。 build()メソッドにfetch呼び出しを残すと、APIが不要な呼び出しで溢れ、アプリの速度が低下します。

完全なソースコードを自由に確認してください

インターフェースを作成するためのエンドポイントはまだいくつかありますが、演習なしの優れたチュートリアルは何ですか?😂

結論

この投稿シリーズでは、Upstashを使用してサーバーレスREST APIを構築し、モバイルアプリケーションで使用する方法について説明しました。

Upstashを使用して次に何を構築するか、またはユースケースに合わせてこのチュートリアルをどのように拡張するかを見てみたいと思います。

この作品が役に立ったと思ったら、ソーシャルメディアページで共有してください。

質問がありますか?コメントを残してください。

エラーを見つけた場合は、何をすべきかを知っています。コメントを残していただければ、できるだけ早くお知らせします。

ハッピーコーディング✌🏿

リファレンス
  • ドキュメントのアップスタッシュ
  • Redis
  • フラッター
  • インターネットからのデータの取得

  1. Nuxt3とサーバーレスRedisの使用を開始する

    はじめに アプリケーションの使用状況を追跡したり、リソースの使用率を制限したり、キャッシュからデータをフェッチしてアプリのパフォーマンスを向上させたりする必要がある場合は、Redisがこれらの要件に対する答えであることがわかります。 Redisは、メモリ内のKey-Valueデータベースです。これはオープンソースであり、RemoteDictionaryServerの略です。 この記事では、Upstash、Redisデータベース、およびVueSSRフレームワークの最近のベータリリースであるNuxt3について説明します。これは、Redisデータベースについて説明する初心者向けの記事で、 Nux

  2. Flutter、サーバーレスフレームワーク、Upstash(REDIS)を備えたフルスタックサーバーレスアプリ-パート1

    この投稿では、データを保存するためのFlutter、Serverless Framework、Upstash、Redisを使用してサーバーレスモバイルアプリケーションを構築します。 Upstashとは? Upstashは、Redis用のサーバーレスデータベースです。 Upstashを使用すると、リクエストごとに支払います。これは、データベースが使用されていないときに課金されないことを意味します。 Upstashはデータベースを構成および管理します。これは、DynamoDBやFaunaなどの他のデータベースの強力な代替手段であり、などの利点があります。 低レイテンシ REDISAPIと同