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

AWS LambdaとサーバーレスRedisで構築するReact Nativeアプリ:リーダーボード機能の実装ガイド

この記事では、React Native、Serverless Framework、Upstashを組み合わせて、リーダーボード(ランキング)の閲覧・更新ができるモバイルアプリケーションを開発する方法を解説します。

モバイルアプリの開発にはReact Nativeを使用し、バックエンドはServerless Frameworkで構築します。バックエンドは、AWS Lambda上で動作するPython関数で構成されています。

1. Upstash Redisを活用する

一般的なリーダーボードアプリでは、ユーザー情報と各ユーザーのスコアを保存する必要があります。これらのデータはスコア順にソートされるため、Redisは最適な選択肢の一つです。

Redisがサポートする「Sorted Set(ソート済みセット)」は、データの保存・追加・削除・範囲検索といった操作を高速に実行できるデータ型です。ソートされたリーダーボードの保存、更新、表示にはまさにうってつけの機能といえます。

1.1 Upstashの始め方

Upstashは、Redis向けのサーバーレスデータベースを提供しています。Redisの仕組みについて詳しく知りたい方は、Redis公式ドキュメントをご確認ください。

今回Upstash Redisを採用した理由は、以下のようなメリットがあるからです。

  • 従量課金制の料金体系(Pricing)

  • ストレージとオペレーションに対する無料枠

  • 非常に簡単な導入

  • 複雑な設定が不要

まずはUpstash Consoleでアカウントを作成し、次にお好みの設定でUpstashデータベースを作成します。これだけで準備完了です!

操作に慣れるために、Upstashコンソールに用意されているCLIでいくつかコマンドを実行してみましょう。

まず、新しいユーザーとそのスコアを「Leaderboard」という名前のSorted Setに追加して、データベースを使い始めます。

ZADD Leaderboard <Score> <User>

続いて、全ユーザーの情報をスコア付きで表示できます。

ZRANGE Leaderboard 0 -1 WITHSCORES

これらの操作をServerless Framework経由でAWS Lambda関数から実行することで、Redisをアプリのバックエンドに接続できます。

2. Serverless Frameworkで関数を作成する

Serverlessは、AWS、Azure、Google Cloudなどのクラウドプロバイダーが提供するサーバーレス関数を扱うためのフレームワークです。ユーザー側からサーバーレス関数を実装・管理できる非常に強力なツールです。

AWS向けにServerless Frameworkをインストール・設定する手順については、Serverlessクイックスタートをご覧ください。

インストールが完了すると、handler.pyとserverless.ymlというファイルが生成されます。

  • serverless.yml

    このファイルでは、実装する関数を定義します。今回必要なのは新しいユーザーの追加と、表示用のリーダーボード取得だけなので、「addScore」と「getLeaderboard」の2つの関数を定義すれば十分です。

	functions:
		addScore:
			handler: handler.addScore
			events:
				- httpApi: 'POST /add'
		getLeaderboard:
			handler: handler.getLeaderboard
			events:
				- httpApi: 'GET /getLeaderboard'
  • handler.py

    このファイルには、モバイルアプリからHTTPリクエストが送信された際にバックエンドで実際に実行されるコードを記述します(serverless.ymlでの定義に基づきます)。

    まず、唯一の依存パッケージであるredisをインポートして設定します。Serverless Frameworkに依存関係を追加するには、「Serverless Python Requirements」プラグインが必要です。以下のコマンドを実行してください。

    serverless plugin install -n serverless-python-requirements
    

    次に、プラグインがserverless.ymlに正しく追加されていることを確認します。

    plugins:
    - serverless-python-requirements
    

    詳細については、serverless-python-requirementsのページをご参照ください。

    最後に、serverless.ymlと同じディレクトリにrequirements.txtファイルを作成し、以下のようにredisの依存関係を追加します。

    redis==4.0.2
    

    これで、handler.py内でUpstash Redisを設定できるようになります。

    import json
    import redis
    
    r = redis.Redis(
    host= 'YOUR_REDIS_ENDPOINT',
    port= 'YOUR_REDIS_PORT',
    password= 'YOUR_REDIS_PASSWORD',
    charset="utf-8",
    decode_responses=True)
    

    Redisの設定が完了したら、ユーザーから呼び出される関数を準備しましょう。

    実装する機能は2つあります。

    1つ目は、新しいユーザーとスコアをリーダーボードに追加する機能です。これはPOSTリクエストとして処理され、ユーザー情報はHTTPリクエストのボディに含めて送信されます。

    {"score": 15,"firstname": "Jack","lastname": "Thang"}
    

    この関数は以下のように実装できます。

    def addScore(event, context):
    info = json.loads(event["body"])
    leaderboard = "Leaderboard"
    score = info["score"]
    player_name = info["firstname"] + "_" + info["lastname"]
    r.zadd(leaderboard, {player_name: score})
    body = {
    "message": "Score added successfully!",
    }
    response = {"statusCode": 200, "body": json.dumps(body)}
    return response
    

    AWS Lambdaが渡すeventパラメータから、スコアとユーザー情報を解析します。

    redisのzadd関数を使うことで、Sorted Set「Leaderboard」にユーザーとスコアを追加できます。実行例:

    Request body: {"score": 15,"firstname": "Jack","lastname": "Thang"}
    
    Response body: {"message": "Score added successfully!"}
    

    2つ目の関数はgetLeaderboardです。この関数はGETリクエストを受け付け、Redisから読み込んだリーダーボードを降順で返します。

    def getLeaderboard(event, context):
    leaderboard = "Leaderboard"
    score_list = r.zrange(leaderboard, 0, -1, withscores=True, desc=True)
    body = {
    "message": "Leaderboard returned successfully!",
    "leaderboard": score_list
    }
    response = {"statusCode": 200, "body": json.dumps(body)}
    return response
    

    実行例:

    Response body: {"message": "Leaderboard returned successfully!", "leaderboard": [["Jack_Thang", 15.0], ["Omer_Aytac", 12.0]]}
    

    最後に、以下のコマンドで関数をデプロイします。

    serverless deploy -v
    

    デプロイ時にService Informationが表示されますので、後で使えるようにエンドポイントを控えておきましょう。

    endpoints:

    POST - https://f571j8y8s1.execute-api.us-east-1.amazonaws.com/add
    
    GET - https://f571j8y8s1.execute-api.us-east-1.amazonaws.com/getLeaderboard
    

    これでサーバーレスバックエンドの準備が整いました。

3. React Nativeでモバイルアプリを開発する

React Nativeは、JavaScriptのコードを書くだけで複数プラットフォーム向けのモバイルアプリを開発できるフレームワークです。

React Nativeでモバイルアプリを開発するには、環境構築とプロジェクト作成が必要です。環境セットアップの手順に従って、最初のモバイルアプリを作成してみてください。

今回のモバイルアプリには2つの画面があります。1つ目は、ユーザーがユーザー情報と一緒に新しいスコアを登録する画面です。

シンプルにするため、ここでは姓・名・スコアのみを入力してもらうことにします。

スコア送信画面は以下のようになります。

AWS LambdaとサーバーレスRedisで構築するReact Nativeアプリ:リーダーボード機能の実装ガイド

この画面では、ユーザーがスコアを入力すると、アプリがServerlessデプロイ時に控えたエンドポイントへHTTPリクエストを送信します。

https://f571j8y8s1.execute-api.us-east-1.amazonaws.com/add

この例で使用している関数は以下の通りです。

async addScore(){
	if(isNaN(this.state.score)){
		Alert.alert("Error", "Please enter a valid score.");
		return;
	}
	if(this.state.firstname == "" || this.state.lastname == "" || this.state.score == null){
		Alert.alert("Error", "Please fill in the blanks.");
		return;
	}
	await fetch('https://f571j8y8s1.execute-api.us-east-1.amazonaws.com/add', {
		method: 'POST',
		headers: {
			Accept: 'application/json',
			'Content-Type': 'application/json',
		},
		body: JSON.stringify({
			firstname: this.state.firstname,
			lastname: this.state.lastname,
			score: parseInt(this.state.score)
		}),
	})
	.then(response => response.json())
	.then(data => {
		if(data.message == "Score added successfully!"){
			Alert.alert("Done!", "Score added successfully!");
		}
		else{
			Alert.alert("Error", "Please try again later.");
		}
	})
	.catch(err => {
		console.error(err)
		Alert.alert("Error", "Please try again later.");
	});
}

ご覧のとおり、POSTリクエストのボディには、ユーザーから入力された値に対応する「firstname」「lastname」「score」というキーが含まれています。

バックエンドからのレスポンスに「Score added successfully!」が含まれていれば、送信したリクエストが正常に受け取られ、スコアの追加に成功したことを意味します。

AWS LambdaとサーバーレスRedisで構築するReact Nativeアプリ:リーダーボード機能の実装ガイド

次に、シンプルなリーダーボード画面をデザインします。「Go to Leaderboard」ボタンをタップすると、リーダーボード画面へ遷移できます。

リーダーボード画面は以下のようになります。

AWS LambdaとサーバーレスRedisで構築するReact Nativeアプリ:リーダーボード機能の実装ガイド

この画面で最も重要なのは、画面が開いたタイミングで以下のエンドポイントへHTTP GETリクエストを送信することです。

https://f571j8y8s1.execute-api.us-east-1.amazonaws.com/getLeaderboard

この処理は、コンポーネントがマウントされた直後に呼び出されるcomponentDidMount関数内で実行できます。

async componentDidMount() {
	await fetch('https://f571j8y8s1.execute-api.us-east-1.amazonaws.com/getLeaderboard',{
		method: 'GET',
		headers: {
			Accept: 'application/json',
			'Content-Type': 'application/json'
		}
	})
	.then(response => response.json())
	.then(data => {
		console.log(data);
		userlist = data.leaderboard;
		this.setState({reRender: !this.state.reRender});
	})
	.catch(err => console.error(err));
}

アプリの完全なソースコードはupstash-react-native-projectで公開されています。

まとめ

この記事では、Serverless Framework経由でAWS Lambda上のPython関数をバックエンドとし、React Nativeでリーダーボード対応のモバイルアプリを開発しました。リーダーボードのデータはUpstash Redisに保存しています。

Upstashで実現できることはまだまだたくさんあります。Redisを使ったリーダーボードアプリの構築は、そのほんの一例にすぎません。

本記事が皆さまのお役に立てば幸いです!

  1. UpstashのPipeline APIでサーバーレスRedisを高速化:複数コマンドを1リクエストで実行

    Upstashは、ネイティブなRedis APIに加えてREST APIもサポートしており、開発者はサーバーレス関数やエッジ関数から接続の問題を気にせずRedisへアクセスできます。しかし、同じ関数内で複数のRedisコマンドを実行する場合、その回数だけデータベースへの呼び出しが発生してしまうという課題がありました。 そこで、コミュニティメンバーの一人である@MasterGates氏が、Discordチャンネルで素晴らしい提案をしてくれました。それが「Pipeline API」です。 Pipeline APIとは Pipeline APIは、RedisのPIPELINEコマンドをREST A

  2. React Nativeでモバイルアプリ開発を始める前に知っておくべき基礎知識

    JavaScriptでアプリを開発することほど素晴らしいことはありません。ただし、モバイルアプリの開発は別話でした。JavaScriptはWebアプリ開発のための言語であり、ネイティブモバイルアプリの開発には使えないのが常識だったのです。Web開発者がネイティブモバイルアプリ開発に足を踏み入れるのは容易ではなく、JavaやObjective-Cなど、目的に応じたプログラミング言語を一から学ぶ必要がありました。そんな常識を打ち破ったのが、Facebook(現Meta)が生み出したReact Nativeです。React Nativeには、AndroidとiOSの両方に対応したクロスプラットフォー