Skip to content

[codex] Implement stub handlers and split handler files#22

Merged
kantacky merged 2 commits intomainfrom
codex/implement-stub-handlers
Mar 27, 2026
Merged

[codex] Implement stub handlers and split handler files#22
kantacky merged 2 commits intomainfrom
codex/implement-stub-handlers

Conversation

@kantacky
Copy link
Copy Markdown
Member

What changed

  • implemented the handlers that had been left as not implemented
  • added user_api client wiring so UsersV1Detail can proxy upstream
  • split the former stub.go and handler_test.go into resource-focused files
  • added handler tests for course registrations, personal calendar items, subjects, and users

Why

These endpoints were still stubbed, so the admin BFF could not serve those routes. The follow-up file split keeps handler code and tests aligned with the existing per-resource layout and makes further changes easier to isolate.

Impact

  • the previously stubbed routes now proxy to the upstream APIs with auth checks and expected response shapes
  • handler tests are easier to navigate by feature
  • runtime now requires USER_API_URL in the external client configuration

Validation

  • GOROOT=/Users/kantacky/.local/share/mise/installs/go/1.25.7 GOCACHE=/Users/kantacky/Developer/dotto-admin-bff-api/.cache/go-build go test -run ^ ./internal/handler ./internal/infrastructure ./cmd/server
  • full go test was not run in this environment because sandbox restrictions block the local listener used by the tests

@kantacky kantacky marked this pull request as ready for review March 27, 2026 05:23
@kantacky kantacky requested review from a team, Copilot, hikaru-0602 and masaya-osuga March 27, 2026 05:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR replaces previously stubbed handler endpoints with working proxy implementations to upstream services (Academic, Announcement, and newly wired User API), and reorganizes handler code/tests into resource-focused files to match the project’s per-resource layout.

Changes:

  • Implemented real handler logic for previously not implemented routes (rooms, course registrations, timetable items, users, etc.) with claim checks and upstream proxying.
  • Added user_api external client wiring (USER_API_URL) and passed it through to the handler so UsersV1Detail can proxy upstream.
  • Split former stub/test files into per-resource handler and test files; added several new handler tests.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
internal/infrastructure/clients.go Adds user_api client creation and includes it in ExternalClients.
cmd/server/main.go Wires the new user client into handler.NewHandler(...).
internal/handler/handler.go Extends Handler to hold userClient and updates constructor signature/validation.
internal/handler/user.go Implements UsersV1Detail as an authenticated upstream proxy.
internal/handler/course_registration.go Implements course registration list/create/delete proxy handlers.
internal/handler/timetable_item.go Implements timetable list/create/delete proxy handlers and adds a slice conversion helper.
internal/handler/room.go Implements rooms CRUD and reservations list proxy handlers.
internal/handler/test_helper_test.go Centralizes test handler construction and admin-claim setup for handler tests.
internal/handler/course_registration_test.go Adds proxy test for course registration creation.
internal/handler/personal_calendar_item_test.go Adds proxy test for personal calendar items list.
internal/handler/user_test.go Adds proxy test for user detail.
internal/handler/subject_test.go Removes now-duplicated local helpers/tests after test split.
internal/handler/stub.go Removes the old not implemented handler stubs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +20 to +26
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotMethod = r.Method
gotPath = r.URL.Path

if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil {
t.Fatalf("decode request body: %v", err)
}
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

The httptest server handler calls t.Fatalf from its own goroutine (net/http serves requests concurrently). In Go tests, Fatal/FailNow should be called only from the test goroutine; this can lead to confusing behavior and makes the test harder to reason about. Capture assertion failures via a channel (or store them and assert after the handler call) instead of calling t.Fatalf inside the server handler.

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +25
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
if got := query.Get("userId"); got != "user-1" {
t.Fatalf("userId = %q, want %q", got, "user-1")
}
if got := query.Get("dates"); got == "" {
t.Fatal("dates query parameter is empty")
}
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

The httptest server handler calls t.Fatalf/t.Fatal from its own goroutine. In Go tests, Fatal/FailNow should be called only from the test goroutine; consider reporting failures back to the main test goroutine via a channel and asserting after the request completes.

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +33
// RoomsV1List 教室一覧を取得する
func (h *Handler) RoomsV1List(c *gin.Context, params api.RoomsV1ListParams) {
if !middleware.RequireAnyClaim(c, "admin", "developer") {
return
}

response, err := h.academicClient.RoomsV1ListWithResponse(c.Request.Context(), &academic_api.RoomsV1ListParams{
Floor: convertSlicePtr[api.DottoFoundationV1Floor, academic_api.DottoFoundationV1Floor](params.Floor),
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

if response.JSON200 == nil {
c.JSON(response.StatusCode(), gin.H{"error": "unexpected response from upstream"})
return
}

c.JSON(http.StatusOK, response.JSON200)
}
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

These handlers implement previously-stubbed room endpoints, but there are no corresponding tests to verify request/response proxying (query/body pass-through, status codes, auth claim enforcement). Adding at least a minimal httptest-based proxy test for one read and one write path would help prevent regressions.

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +64
// TimetableItemsV1List 時間割を取得する
func (h *Handler) TimetableItemsV1List(c *gin.Context, params api.TimetableItemsV1ListParams) {
if !middleware.RequireAnyClaim(c, "admin", "developer") {
return
}

response, err := h.academicClient.TimetableItemsV1ListWithResponse(c.Request.Context(), &academic_api.TimetableItemsV1ListParams{
Year: params.Year,
Semesters: convertSlice[api.DottoFoundationV1CourseSemester, academic_api.DottoFoundationV1CourseSemester](params.Semesters),
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

if response.JSON200 == nil {
c.JSON(response.StatusCode(), gin.H{"error": "unexpected response from upstream"})
return
}

c.JSON(http.StatusOK, gin.H{
"items": response.JSON200.TimetableItems,
})
}

// TimetableItemsV1Create 時間割に追加する
func (h *Handler) TimetableItemsV1Create(c *gin.Context) {
if !middleware.RequireAnyClaim(c, "admin", "developer") {
return
}

var req academic_api.TimetableItemRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

response, err := h.academicClient.TimetableItemsV1CreateWithResponse(c.Request.Context(), req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

if response.JSON201 == nil {
c.JSON(response.StatusCode(), gin.H{"error": "unexpected response from upstream"})
return
}

c.JSON(http.StatusCreated, gin.H{
"item": response.JSON201.TimetableItem,
})
}
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

These handlers implement previously-stubbed timetable endpoints, but there are no tests covering the proxy behavior (semester param mapping, request body binding, status code handling, and auth claim enforcement). Adding at least one list/create/delete test using httptest would improve confidence and catch upstream contract changes.

Copilot uses AI. Check for mistakes.
@kantacky kantacky merged commit fb458f2 into main Mar 27, 2026
6 checks passed
@kantacky kantacky deleted the codex/implement-stub-handlers branch March 27, 2026 05:33
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.

3 participants