Skip to content

Feat/walt/api seaweedfs#20

Open
nakatashingo wants to merge 8 commits into
developfrom
feat/walt/api-seaweedfs
Open

Feat/walt/api seaweedfs#20
nakatashingo wants to merge 8 commits into
developfrom
feat/walt/api-seaweedfs

Conversation

@nakatashingo
Copy link
Copy Markdown
Collaborator


[feat] 花火画像を SeaweedFS に保存する設計に変更

背景

これまで花火のバイナリデータ(pixel_data)を PostgreSQL
に直接保存していたが、画像ファイルをオブジェクトストレージ(SeaweedFS)
に保存する設計に変更した。
バイナリ変換処理はサーバーから削除し、各クライアント(モバイル・Unity)
が行う責務とする。


変更内容

インフラ

  • SeaweedFS を Docker Compose に追加(S3 互換のオブジェクトストレージ)
  • app サービスの起動前に SeaweedFS が立ち上がるよう depends_on を追加

API の変更

  • POST /fireworks — 画像ファイルを受け取り SeaweedFS
    にアップロード。pixel_data の生成処理を削除
  • GET /fireworks — クエリパラメータ from /
    to(日付)でフィルタリング可能に
  • GET /fireworks/{id} — クエリパラメータ resolution
    を追加(現時点では将来拡張用)
  • GET /fireworks/{id}/image — 新規追加 元画像の URL へリダイレクト

レスポンスの変更

FireworkResponse に imageUrl フィールドを追加。

{
"id": 1,
"imageUrl": "http://localhost:8333/fireworks/images/xxx.jpg",
"isShareable": true,
"pixelData": [],
"createdAt": "...",
"updatedAt": "..."
}

要件外の改善

SeaweedFS の URL(http://seaweedfs:8333)は Docker
内部のホスト名のため、コンテナ外からアクセスできない問題を修正。
STORAGE_PUBLIC_URL 環境変数を追加し、S3 API 通信用エンドポイントと公開
URL を分離した。


動作確認手順

前提

/tmp に確認用の画像を用意しておく

cp /path/to/your/image.png /tmp/test.png

  1. コンテナを起動する

docker compose up --build

ログに Listening on :8080 が出たら準備完了。

  1. 花火を作成する(画像アップロード)

curl -X POST http://localhost:8080/fireworks
-F "image=@/tmp/test.png"
-F "is_shareable=true"

期待するレスポンス(HTTP 201)

{
"id": 1,
"imageUrl": "http://localhost:8333/fireworks/images/xxxxxxxx.jpg",
"isShareable": true,
"pixelData": [],
"createdAt": "...",
"updatedAt": "..."
}

imageUrl が http://localhost:8333/... になっていることを確認する。

  1. 画像を取得する

{id} は手順2のレスポンスの id に置き換える

curl -L http://localhost:8080/fireworks/{id}/image -o
/tmp/downloaded.jpg && open /tmp/downloaded.jpg

アップロードした画像が表示されれば成功。

  1. 一覧取得・imageUrl の確認

全件取得

curl http://localhost:8080/fireworks | jq

日付フィルタ

curl "http://localhost:8080/fireworks?from=2026-05-01&to=2026-05-31" |
jq

  1. 1件取得

curl http://localhost:8080/fireworks/{id} | jq

  1. 更新

curl -X PUT http://localhost:8080/fireworks/{id}
-H "Content-Type: application/json"
-d '{"isShareable": false}'

  1. 削除

curl -X DELETE http://localhost:8080/fireworks/{id}

削除後に再度取得して 404 Not Found が返ることを確認する。

curl -i http://localhost:8080/fireworks/{id}

→ HTTP/1.1 404 Not Found


変更ファイル一覧

  • docker-compose.yaml — SeaweedFS サービス・環境変数の追加
  • openapi.yaml — imageUrl・新エンドポイント・クエリパラメータの追加
  • api/domain/firework.go — ImagePath フィールドの追加
  • api/infra/storage.go — 新規 SeaweedFS(S3 互換)クライアントの実装
  • api/openapi/openapi.gen.go — OpenAPI 仕様に合わせた型・ルートの更新
  • api/usecase/firework_usecase.go —
    バイナリ変換削除・ストレージ操作の追加
  • api/handler/firework_handler.go —
    新エンドポイント・クエリパラメータの対応
  • api/main.go — StorageClient の初期化・DI
  • api/go.mod / api/go.sum — AWS SDK v2 の依存追加

Copy link
Copy Markdown
Contributor

@uchida189 uchida189 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

コメントしました!

Comment thread api/domain/firework.go
PixelData []byte `gorm:"column:pixel_data"` // ピクセルデータ
gorm.Model
IsShareable bool `gorm:"column:is_shareable"`
PixelData []byte `gorm:"column:pixel_data"` // 旧レコード互換。新レコードは nil
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pixelDataはいらないのでは?

Comment thread openapi.yaml
# 再利用可能なコンポーネントを定義するセクション
description: "花火が削除されました"
content: {}
/fireworks/{id}/image:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

このAPIは現状では不要かもしれない。
/firewoks/fireworks/{id}のレスポンスに含まれるimageURLが、/fireworks/{id}/imageで返されるURLと同じものなので。

Comment thread openapi.yaml
required:
- id
- isShareable
- pixelData
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pixelDataは不要で、
imageURLがrequireだと思います

Comment thread openapi.yaml
@@ -157,9 +186,10 @@
items:
type: boolean
description: "各ピクセルの状態(点灯/消灯)"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pixelDataは不要


// is_shareableの値を取得・変換
isShareable := false
if values, exists := form.Value["is_shareable"]; exists && len(values) > 0 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここ書いたの俺なんだけど、is_shareableじゃなくてisShareableに直しておいてほしいです!
ここのせいでisShareableが指定できなくなってた・・・

Comment thread docker-compose.yaml
volumes:
- ./api:/app
working_dir: /app
command: sh -c "go mod tidy && go run main.go"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

すみません、このcommandの行を削除して欲しいです。
ここのせいでGoのホットリロードが効かなくなってた

file, err := req.Image.Bytes()
if err != nil {
return openapi.FireworkResponse{}, fmt.Errorf("failed to open image file: %w", err)
func (uc *fireworkUsecase) GetFireworkImageURL(ctx context.Context, id int64) (string, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これいらないと思った。
理由はopenapi.yamlにコメントした通りで/fireworks/{id}/imageがいらないと思うため

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants