Skip to content

マイクロサービスで使用できるRESTfulとgRPC両対応のユーザー残高管理サービス実装例

Notifications You must be signed in to change notification settings

kaitolucifer/user-balance-management

Repository files navigation

アーキテクチャ

アーキテクチャー図

  • 本プロジェクトは上の図で示したオニオンアーキテクチャに従う
  • ディレクトリ構造
    • domain → Domain層: Domainモデル、Repositoryインタフェース、Usecaseインタフェース
    • usecase → Use Case層: Usecaseインタフェースの実装
    • infrastructure → Infrastructure層: DBドライバー、Repositoryインタフェースの実装
    • presentation → Presentation層: http RESTfulハンドラとgRPCハンドラの実装
    • injector: 各層の依存性注入用関数の実装
    • app: アプリケーションの設定と起動関連
    • migrations: スキーマ定義と初期データ投入用のDBマイグレーションスクリプト

アプリケーション起動方法

docker-compose up -d
curl localhost:8080 # RESTfulハンドラ使用時のヘルスチェック

FAQ

  • RESTfulハンドラとgRPCハンドラの切り替え方法は?

    デフォルトはgRPCハンドラを使用する。DockerfileCMD ["./webapp", "-dbhost", "db"]CMD ["./webapp", "-dbhost", "db", "-use_grpc=false"]に、docker-compose.ymlで解放ポートを8080に変更すればRESTfulハンドラに切り替えられる。

  • エラーや障害によってリクエストが再送される場合の対処法は?

    残高加減算処理時、一意の取引IDtransaction_idが必要で、再送される場合はエラーメッセージを返すようにしている。

  • 残高加減算のデータ整合性はどのように実現されている?

    残高加減算処理と取引履歴の挿入はDBトランザクションを使用してデータ整合性を実現している。

  • Dirty Read、Non-Repeatable Read、Phantom Readについてはどう対処している?

    PostgreSQLのデフォルトのトランザクション分離レベルはREAD COMMITTEDのため、Dirty Readは発生しない。 Non-Repeatable ReadとPhantom Readは理論上発生する可能性があるが、サービス内では特別な処置をしていないため、サービスの呼び出し側で対処する必要がある。

gRPC APIの使用方法

インタフェースの定義はpresentation/grpc/proto/user_balance.protoから確認できる。protocで各言語のコードが生成できる。Goの生成コードの使用方法は以下になる。

package main

import (
  "context"
  "fmt"
  "log"

  "github.com/kaitolucifer/grpc-client/proto" // 生成コード
  "google.golang.org/grpc"
)

func main() {	
  conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
  if err != nil {
    log.Fatalf("could not connect: %v", err)
  }
  defer conn.Close()
  
  client := proto.NewUserBalanceClient(conn)
  req := &proto.GetUserBalanceRequest{
    UserId: "test_user1",
  }
  res, err := client.GetBalanceByUserID(context.Background(), req)
  if err != nil {
    log.Fatalf("error while calling gRPC: %s", err)
  }
  fmt.Println(res.GetBalance())
}

RESTful APIドキュメンテーション

  • ヘルスチェック

    • URL

      /

    • メソッド:

      GET

    • URLパラメータ:

      None

    • Body:

      None

    • レスポンス:

      • 200

        {
          "status": "success",
          "message": "healthy"
        }
  • 残高参照

    • URL

      /balance/{user_id}

    • メソッド:

      GET

    • URLパラメータ:

      user_id: int

    • Body:

      None

    • レスポンス:

      • 200

        {
          "status": "success",
          "balance": 1000
        }
      • 400 / 404

        {
          "status": "fail",
          "message": "message"
        }
      • 500

        {
          "status": "error",
          "message": "message"
        }
  • 残高加算

    • URL

      /balance/add/{user_id}

    • メソッド:

      PATCH

    • URLパラメータ:

      user_id: int

    • Body:

      {
        "amount": 1000,
        "transaction_id": "unique transaction_id"
      }
    • レスポンス:

      • 200

        {
          "status": "success",
          "message": "user balance has been added successfully"
        }
      • 400 / 404 / 422

        {
          "status": "fail",
           "message": "message"
        }
      • 500

        {
          "status": "error",
          "message": "message"
        }
  • 残高減算

    • URL

      /balance/reduce/{user_id}

    • メソッド:

      PATCH

    • URLパラメータ:

      user_id: int

    • Body:

      {
        "amount": 1000,
        "transaction_id": "unique transaction_id"
      }
    • レスポンス:

      • 200

        {
          "status": "success",
          "message": "user balance has been added successfully"
        }
      • 400 / 404 / 409 / 422

        {
          "status": "fail",
          "message": "message"
        }
      • 500

        {
          "status": "error",
          "message": "message"
        }
  • 残高一斉加算

    • URL

      /balance/add-all

    • メソッド:

      PATCH

    • URLパラメータ:

      None

    • Body:

      {
        "amount": 1000,
        "transaction_id": "unique transaction_id"
      }
    • レスポンス:

      • 200

        {
          "status": "success",
          "message": "user balance has been added successfully"
        }
      • 400 / 404 / 422

        {
          "status": "fail",
          "message": "message"
        }
      • 500

        {
          "status": "error",
          "message": "message"
        }

About

マイクロサービスで使用できるRESTfulとgRPC両対応のユーザー残高管理サービス実装例

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published