Skip to content

Commit 1171bfc

Browse files
hikaru-0602Copilot
andauthored
Subject APIを追加 (#11)
* common domain * course domain * timatable domain * faculty domain * subject domain * subject_category domain * SubjectのAPIURL * APIクライアントの生成をまとめた * 外部のクライアントを一括初期化する処理に修正 * courseの型変換 * timetableの型変換 * facultyの型変換 * 科目区分の型変換 * Subjectの型変換 * HandlerをWithパターンに変更 * Withパターンに対応 * facultyの変換関数を追加 * facultyのHandler実装 * Handlerの初期化にfacultyも追加 * facultyのService実装 * facultyのRepository実装 * courseを追加 * courseの変換関数を追加 * courseのHandler実装 * Handlerの初期化にcourse追加 * courseのRepository実装 * courseのService実装 * timetable追加 * timetable追加 * timetableのHandler実装 * timetable追加 * timetableのRepository実装 * timetableのService実装 * subject_category追加 * subject_category * subject_category * subject_categoryのHandler実装 * subject_categoryのRepository実装 * subject_categoryのService実装 * subject追加 * subject * subject追加 * subjectのHandler実装 * subjectのService実装 * subjectのRepository実装 * courseのRepositoryモック実装 * timetableのRepositoryモック実装 * facultyのRepositoryモック実装 * subject_categoryのRepositoryモック実装 * subjectのRepositoryモック実装 * courseのHandlerテスト実装 * timetableのHandlerテスト実装 * facultyのHandlerテスト実装 * subject_categoryのHandlerテスト実装 * subjectのHandlerテスト実装 * CDにSubjectの環境変数を追加 * converterファイルをAPIごとに切り分け(お試し実装) * リクエストにタイムアウトを設定 * デフォルト値を削除 * setupMockを使用してテストごとにモックを設定 * ドメインモデルからJsonの型を外した * facultyにカスタムID追加 * courseをカスタムIDに * timetableをカスタムIDに * announcement, subject_category, subjectをカスタムIDに * テスト削除 * Handlerに直接挿入 * 必要ないので削除 * 削除 * 削除 * クライアント持つ * そのまま返す * 修正 * Subject関連も薄くした * クライアントチェック追加 * Update internal/handler/day_of_week_timetable_slot.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update internal/handler/subject.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update internal/handler/subject_category.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update internal/handler/announcement.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update internal/handler/faculty.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update internal/handler/course.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update internal/handler/subject.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent c2a3177 commit 1171bfc

19 files changed

Lines changed: 619 additions & 955 deletions

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
ANNOUNCEMENT_API_URL=
22
GOOGLE_APPLICATION_CREDENTIALS=
33
GOOGLE_CLOUD_PROJECT=
4+
SUBJECT_API_URL=

.github/workflows/cd.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,5 +125,6 @@ jobs:
125125
region: ${{ vars._DEPLOY_REGION }}
126126
env_vars: |
127127
ANNOUNCEMENT_API_URL=${{ vars.ANNOUNCEMENT_API_URL }}
128+
SUBJECT_API_URL=${{ vars.SUBJECT_API_URL }}
128129
env_vars_update_strategy: overwrite
129130
secrets_update_strategy: overwrite

cmd/server/main.go

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,16 @@ package main
33
import (
44
"context"
55
"log"
6-
"os"
76

87
firebase "firebase.google.com/go/v4"
98
api "github.com/fun-dotto/api-template/generated"
10-
"github.com/fun-dotto/api-template/generated/external/announcement_api"
119
"github.com/fun-dotto/api-template/internal/handler"
10+
"github.com/fun-dotto/api-template/internal/infrastructure"
1211
"github.com/fun-dotto/api-template/internal/middleware"
13-
"github.com/fun-dotto/api-template/internal/repository"
14-
"github.com/fun-dotto/api-template/internal/service"
1512
"github.com/getkin/kin-openapi/openapi3"
1613
"github.com/gin-gonic/gin"
1714
"github.com/joho/godotenv"
1815
oapimiddleware "github.com/oapi-codegen/gin-middleware"
19-
"google.golang.org/api/idtoken"
2016
)
2117

2218
func main() {
@@ -46,31 +42,12 @@ func main() {
4642
router.Use(oapimiddleware.OapiRequestValidator(spec))
4743
router.Use(middleware.FirebaseAuth(authClient))
4844

49-
announcementAPIURL := os.Getenv("ANNOUNCEMENT_API_URL")
50-
if announcementAPIURL == "" {
51-
log.Fatal("ANNOUNCEMENT_API_URL is required")
52-
}
53-
// 認証付きHTTPクライアントを作成
54-
announcementAPIAuthClient, err := idtoken.NewClient(ctx, announcementAPIURL)
45+
clients, err := infrastructure.NewExternalClients(ctx)
5546
if err != nil {
56-
log.Fatal("Failed to create auth client:", err)
47+
log.Fatalf("Failed to initialize external clients: %v", err)
5748
}
5849

59-
// 生成されたクライアントに認証付きHTTPクライアントを注入
60-
apiClient, err := announcement_api.NewClientWithResponses(
61-
announcementAPIURL,
62-
announcement_api.WithHTTPClient(announcementAPIAuthClient),
63-
)
64-
if err != nil {
65-
log.Fatal("Failed to create API client:", err)
66-
}
67-
68-
// Initialize layers
69-
announcementRepo := repository.NewAnnouncementRepository(apiClient)
70-
announcementService := service.NewAnnouncementService(announcementRepo)
71-
72-
// Register handlers
73-
h := handler.NewHandler(announcementService)
50+
h := handler.NewHandler(clients.Announcement, clients.Subject)
7451
api.RegisterHandlers(router, h)
7552

7653
addr := ":8080"

go.mod

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ require (
99
github.com/joho/godotenv v1.5.1
1010
github.com/oapi-codegen/gin-middleware v1.0.2
1111
github.com/oapi-codegen/runtime v1.1.2
12-
github.com/stretchr/testify v1.11.1
1312
google.golang.org/api v0.231.0
1413
)
1514

@@ -35,7 +34,6 @@ require (
3534
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3635
github.com/cloudwego/base64x v0.1.6 // indirect
3736
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
38-
github.com/davecgh/go-spew v1.1.1 // indirect
3937
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
4038
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
4139
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
@@ -74,7 +72,6 @@ require (
7472
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
7573
github.com/perimeterx/marshmallow v1.1.5 // indirect
7674
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
77-
github.com/pmezard/go-difflib v1.0.0 // indirect
7875
github.com/quic-go/qpack v0.5.1 // indirect
7976
github.com/quic-go/quic-go v0.55.0 // indirect
8077
github.com/rogpeppe/go-internal v1.14.1 // indirect

internal/domain/announcement.go

Lines changed: 0 additions & 20 deletions
This file was deleted.

internal/external/announcement.go

Lines changed: 0 additions & 27 deletions
This file was deleted.

internal/handler/announcement.go

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55

66
"github.com/gin-gonic/gin"
77

8-
api "github.com/fun-dotto/api-template/generated"
8+
"github.com/fun-dotto/api-template/generated/external/announcement_api"
99
"github.com/fun-dotto/api-template/internal/middleware"
1010
)
1111

@@ -15,15 +15,18 @@ func (h *Handler) AnnouncementsV1List(c *gin.Context) {
1515
return
1616
}
1717

18-
announcements, err := h.announcementService.List(c.Request.Context())
18+
response, err := h.announcementClient.AnnouncementsV1ListWithResponse(c.Request.Context(), nil)
1919
if err != nil {
2020
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
2121
return
2222
}
2323

24-
c.JSON(http.StatusOK, api.AnnouncementsV1List200JSONResponse{
25-
Announcements: ToAPIAnnouncements(announcements),
26-
})
24+
if response.JSON200 == nil {
25+
c.JSON(response.StatusCode(), gin.H{"error": "unexpected response from upstream"})
26+
return
27+
}
28+
29+
c.JSON(http.StatusOK, response.JSON200)
2730
}
2831

2932
// AnnouncementsV1Detail 詳細を取得する
@@ -32,15 +35,18 @@ func (h *Handler) AnnouncementsV1Detail(c *gin.Context, id string) {
3235
return
3336
}
3437

35-
announcement, err := h.announcementService.Detail(c.Request.Context(), id)
38+
response, err := h.announcementClient.AnnouncementsV1DetailWithResponse(c.Request.Context(), id)
3639
if err != nil {
3740
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
3841
return
3942
}
4043

41-
c.JSON(http.StatusOK, api.AnnouncementsV1Detail200JSONResponse{
42-
Announcement: ToAPIAnnouncement(announcement),
43-
})
44+
if response.JSON200 == nil {
45+
c.JSON(response.StatusCode(), gin.H{"error": "unexpected response from upstream"})
46+
return
47+
}
48+
49+
c.JSON(http.StatusOK, response.JSON200)
4450
}
4551

4652
// AnnouncementsV1Create 新規作成する
@@ -49,21 +55,24 @@ func (h *Handler) AnnouncementsV1Create(c *gin.Context) {
4955
return
5056
}
5157

52-
var req api.AnnouncementServiceAnnouncementRequest
58+
var req announcement_api.AnnouncementRequest
5359
if err := c.ShouldBindJSON(&req); err != nil {
5460
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
5561
return
5662
}
5763

58-
announcement, err := h.announcementService.Create(c.Request.Context(), ToDomainAnnouncementRequest(&req))
64+
response, err := h.announcementClient.AnnouncementsV1CreateWithResponse(c.Request.Context(), req)
5965
if err != nil {
6066
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
6167
return
6268
}
6369

64-
c.JSON(http.StatusCreated, api.AnnouncementsV1Create201JSONResponse{
65-
Announcement: ToAPIAnnouncement(announcement),
66-
})
70+
if response.JSON201 == nil {
71+
c.JSON(response.StatusCode(), gin.H{"error": "unexpected response from upstream"})
72+
return
73+
}
74+
75+
c.JSON(http.StatusCreated, response.JSON201)
6776
}
6877

6978
// AnnouncementsV1Delete 削除する
@@ -72,13 +81,18 @@ func (h *Handler) AnnouncementsV1Delete(c *gin.Context, id string) {
7281
return
7382
}
7483

75-
if err := h.announcementService.Delete(c.Request.Context(), id); err != nil {
84+
response, err := h.announcementClient.AnnouncementsV1DeleteWithResponse(c.Request.Context(), id)
85+
if err != nil {
7686
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
7787
return
7888
}
7989

90+
if response.StatusCode() != http.StatusNoContent {
91+
c.JSON(response.StatusCode(), gin.H{"error": "unexpected response from upstream"})
92+
return
93+
}
94+
8095
c.Status(http.StatusNoContent)
81-
c.Writer.WriteHeaderNow()
8296
}
8397

8498
// AnnouncementsV1Update 更新する
@@ -87,19 +101,22 @@ func (h *Handler) AnnouncementsV1Update(c *gin.Context, id string) {
87101
return
88102
}
89103

90-
var req api.AnnouncementServiceAnnouncementRequest
104+
var req announcement_api.AnnouncementRequest
91105
if err := c.ShouldBindJSON(&req); err != nil {
92106
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
93107
return
94108
}
95109

96-
announcement, err := h.announcementService.Update(c.Request.Context(), id, ToDomainAnnouncementRequest(&req))
110+
response, err := h.announcementClient.AnnouncementsV1UpdateWithResponse(c.Request.Context(), id, req)
97111
if err != nil {
98112
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
99113
return
100114
}
101115

102-
c.JSON(http.StatusOK, api.AnnouncementsV1Update200JSONResponse{
103-
Announcement: ToAPIAnnouncement(announcement),
104-
})
116+
if response.JSON200 == nil {
117+
c.JSON(response.StatusCode(), gin.H{"error": "unexpected response from upstream"})
118+
return
119+
}
120+
121+
c.JSON(http.StatusOK, response.JSON200)
105122
}

0 commit comments

Comments
 (0)