iiitl / iiitl/Opensource_Compass
Refactor Auth Service: Replace `map[string]interface{}` with a Typed `GitHubUser` Struct
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 16
- PR merge metrics
- No merged PRs in 30d
Description
### ๐ Description
In `backend/auth-service/internal/github/oauth.go`, the `FetchUser()` function returns `map[string]interface{}`:
```go
func FetchUser(token string) (map[string]interface{}, error) {
// ...
var user map[string]interface{}
json.Unmarshal(bodyBytes, &user)
// ...
return user, nil
}
```
This is a significant **type-safety problem** in Go:
1. Every caller must perform repetitive, brittle type assertions like `user["login"].(string)` โ if GitHub ever changes a field type, this panics at runtime (not compile time)
2. The linter and compiler **cannot catch typos** in field names โ `user["loginn"]` compiles fine but returns `nil` silently
3. It's impossible to tell which GitHub API fields the code actually depends on without tracing through all callers
4. There are multiple `fmt.Printf("DEBUG: ...")` debug statements still in production code that leak internal info to logs
The refactor requires introducing a clean `GitHubUser` struct, updating JSON unmarshaling, removing all debug `fmt.Printf` calls, updating callers to use the typed struct, and ensuring nothing breaks.
---
### ๐ Files to Change
- `backend/auth-service/internal/github/oauth.go` โ define `GitHubUser`, rewrite `FetchUser`
- Any caller in `backend/auth-service/` that uses the return value of `FetchUser` (find them with `grep -r "FetchUser" backend/auth-service/`)
---
### ๐ Problems in the Current Code
```go
// oauth.go - many issues in one function:
var user map[string]interface{} // โ untyped map
json.Unmarshal(bodyBytes, &user) // โ silently drops unmarshal errors
fmt.Printf("DEBUG: GitHub User Response: %s\n", string(bodyBytes)) // โ leaks raw API response to logs
if errMsg, ok := user["message"].(string); ok { // โ type assertion, can panic
fmt.Printf("DEBUG: GitHub API Error: %s\n", errMsg) // โ debug print in production
}
if user["email"] == nil || user["email"] == "" { // โ comparing interface{} to "" won't work
// ...
}
```
---
### โ What To Do
**Step 1 โ Define a `GitHubUser` struct in a new file `user.go`:**
```go
// backend/auth-service/internal/github/user.go
package github
// GitHubUser represents the fields we use from the GitHub /user API response.
// Reference: https://docs.github.com/en/rest/users/users#get-the-authenticated-user
type GitHubUser struct {
ID int64 `json:"id"`
Login string `json:"login"` // GitHub username
Name string `json:"name"` // Display name (may be empty)
Email string `json:"email"` // Public email (may be empty)
AvatarURL string `json:"avatar_url"`
HTMLURL string `json:"html_url"`
// Error fields (returned by GitHub on failure)
Message string `json:"message,omitempty"`
}
```
**Step 2 โ Rewrite `FetchUser` to use the struct:**
```go
func FetchUser(token string) (*GitHubUser, error) {
req, err := http.NewRequest("GET", "https://api.github.com/user", nil)
if err != nil {
return nil, fmt.Errorf("creating request: %w", err)
}
req.Header.Set("Authorization", "token "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("calling github API: %w", err)
}
defer resp.Body.Close()
var user GitHubUser
if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
return nil, fmt.Errorf("decoding response: %w", err)
}
// GitHub returns a "message" field in the JSON body on error (e.g., bad token)
if user.Message != "" {
return nil, fmt.Errorf("github API error: %s", user.Message)
}
// Fetch primary email if not public
if user.Email == "" {
email, err := FetchUserEmail(token)
if err != nil {
log.Printf("FetchUser: could not fetch email for %s: %v", user.Login, err)
} else {
user.Email = email
}
}
return &user, nil
}
```
**Step 3 โ Update all callers.**
Run this to find them:
```bash
grep -rn "FetchUser" backend/auth-service/
```
Callers will be accessing map fields like `user["id"]`, `user["login"]`. Replace each with struct field access: `user.ID`, `user.Login`, etc.
**Step 4 โ Remove all `fmt.Printf("DEBUG: ...")` lines from `oauth.go`.**
Replace useful debug logging with proper `log.Printf` calls that don't dump raw API responses.
---
### ๐ Acceptance Criteria
- [ ] A `GitHubUser` struct is defined with at minimum: `ID`, `Login`, `Name`, `Email`, `AvatarURL` fields
- [ ] `FetchUser` returns `(*GitHubUser, error)` โ not `(map[string]interface{}, error)`
- [ ] All callers of `FetchUser` across the auth-service are updated to use struct fields
- [ ] All `fmt.Printf("DEBUG: ...")` lines are removed from `oauth.go`
- [ ] JSON unmarshal errors are properly handled (not silently swallowed)
- [ ] Auth service compiles: `cd backend/auth-service && go build ./...`
- [ ] GitHub OAuth login still works end-to-end (test by logging in with your GitHub account)
---
### ๐ก Technical Hints
- The GitHub API returns an `"id"` field as a JSON number. In Go, unmarshal it into `int64` (not `int`) since GitHub user IDs exceed the range of 32-bit integers
- `user["email"] == ""` does NOT work when `user` is a `map[string]interface{}` โ you're comparing `interface{}` to a string, which is always `false`. With the typed struct, `user.Email == ""` works correctly. This is one of the real bugs you're fixing
- Check if the auth-service handler that calls `FetchUser` passes fields through to `upsert`/`CreateOrGet` in the core service โ those field names need to match your new struct fields
---
### ๐ Getting Started
1. Fork the repository
2. Create a branch: `git checkout -b refactor/issue-31-typed-github-user`
3. Create `backend/auth-service/internal/github/user.go` with the new struct
4. Rewrite `FetchUser` in `oauth.go`
5. Find and update all callers: `grep -rn "FetchUser" backend/auth-service/`
6. Remove DEBUG prints
7. Run: `cd backend/auth-service && go build ./...`
8. Do a full login flow test
9. Open a PR!
Contributor guide
Research direction
Start with backend/auth-service/internal/github/oauth.go and add the GitHubUser definition in backend/auth-service/internal/github/user.go, then use grep -rn "FetchUser" backend/auth-service/ to locate callers. Run cd backend/auth-service && go build ./... and verify the acceptance criteria: typed fields, handled JSON errors, removed DEBUG prints, and a working GitHub OAuth login flow.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github, go
- Domain
- api, authentication, backend
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100