Skip to content

Commit f3bc8fa

Browse files
committed
Error Handling
1. 429 now prompts for entering a new API Token 2. Handling panic exits for user not available and nil pointer errors
1 parent a8a456e commit f3bc8fa

File tree

7 files changed

+237
-85
lines changed

7 files changed

+237
-85
lines changed

cmd/handlers.go

+73-14
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmd
33
import (
44
"context"
55
"fmt"
6+
"go-github/helper"
67
"go-github/service"
78
"go-github/views"
89

@@ -25,7 +26,7 @@ func handleMainPage(ctx *gin.Context) {
2526
if strings.TrimSpace(ctx.Query("username")) == "" {
2627
getIndexHandler(ctx)
2728
} else {
28-
getUserHandler(ctx)
29+
getUserHandler(ctx, false)
2930
}
3031
}
3132

@@ -39,26 +40,33 @@ func getIndexHandler(ctx *gin.Context) {
3940
render(ctx, http.StatusOK, views.Index(emptyUser))
4041
}
4142

42-
func getUserHandler(ctx *gin.Context) {
43-
_, cancel := context.WithTimeout(context.Background(), appTimeout)
44-
username := ctx.Query("username")
45-
username = strings.TrimSpace(username)
46-
47-
defer cancel()
48-
43+
func getUser(ctx *gin.Context, username string, force bool) {
4944
user, err := service.FetchEntryFromXata(username)
5045

5146
if err != nil {
5247
fmt.Println(err)
53-
user, _ = service.FetchGitHubProfile(username)
54-
if user == nil {
55-
user = &views.GitHubUser{
56-
Name: "User not found",
48+
var err error
49+
user, err = service.FetchGitHubProfile(username, force)
50+
51+
fmt.Println(err)
52+
if err != nil {
53+
if strings.Contains(err.Error(), "404") {
54+
user = &views.GitHubUser{
55+
Name: "User not found",
56+
}
57+
ctx.JSON(http.StatusNotFound, user)
58+
} else if strings.Contains(err.Error(), "429") {
59+
ctx.JSON(http.StatusTooManyRequests, gin.H{
60+
"error": err.Error(),
61+
})
62+
} else {
63+
ctx.JSON(http.StatusInternalServerError, gin.H{
64+
"error": err.Error(),
65+
})
5766
}
58-
ctx.JSON(http.StatusNotFound, user)
5967
return
6068
}
61-
_, err := service.CreateNewEntry(user)
69+
_, err = service.CreateNewEntry(user)
6270
if err != nil {
6371
fmt.Println(err)
6472
}
@@ -67,3 +75,54 @@ func getUserHandler(ctx *gin.Context) {
6775
//serve user as JSON
6876
ctx.JSON(http.StatusOK, user)
6977
}
78+
79+
func getUserHandler(ctx *gin.Context, force bool) {
80+
_, cancel := context.WithTimeout(context.Background(), appTimeout)
81+
username := ctx.Query("username")
82+
username = strings.TrimSpace(username)
83+
84+
defer cancel()
85+
86+
if username == "" {
87+
ctx.JSON(http.StatusBadRequest, gin.H{
88+
"error": "username is required",
89+
})
90+
return
91+
}
92+
93+
getUser(ctx, username, force)
94+
95+
}
96+
97+
func postTokenHandler(ctx *gin.Context) {
98+
// get token
99+
100+
type TokenRequest struct {
101+
Token string `json:"token"`
102+
Username string `json:"username"`
103+
}
104+
105+
request := TokenRequest{}
106+
if err := ctx.ShouldBindJSON(&request); err != nil {
107+
ctx.JSON(http.StatusBadRequest, gin.H{
108+
"error": err.Error(),
109+
})
110+
return
111+
}
112+
113+
token := request.Token
114+
username := request.Username
115+
116+
if strings.TrimSpace(token) != "" {
117+
err := helper.SetEnvVariable("GITHUB_TOKEN", token)
118+
119+
if err != nil {
120+
ctx.JSON(http.StatusBadRequest, gin.H{
121+
"error": err.Error(),
122+
})
123+
return
124+
}
125+
126+
getUser(ctx, username, true)
127+
}
128+
}

cmd/routes.go

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ func (app *Config) Routes() {
2020
})
2121
})
2222

23+
app.Router.POST("/token", postTokenHandler)
24+
2325
app.Router.NoRoute(func(ctx *gin.Context) {
2426
ctx.Status(http.StatusNotFound)
2527
})

helper/github-helper.go

+29-23
Original file line numberDiff line numberDiff line change
@@ -8,51 +8,57 @@ import (
88
"golang.org/x/oauth2"
99
)
1010

11-
var githubAPIKey = GetEnvVariable("GITHUB_TOKEN")
12-
1311
type GithubClientSingleton struct {
1412
GithubClient *github.Client
15-
apiKey string
1613
}
1714

1815
var githubInstance *GithubClientSingleton
1916

20-
func GetGithubClientInstance() *GithubClientSingleton {
21-
if githubInstance == nil {
17+
func GetGithubClientInstance(force bool) *GithubClientSingleton {
18+
19+
if force {
2220
lock.Lock()
21+
createGithubClient()
2322
defer lock.Unlock()
24-
if githubInstance == nil {
25-
fmt.Println("Creating single instance now.")
26-
githubInstance = &GithubClientSingleton{
27-
apiKey: xataAPIKey,
28-
}
29-
30-
githubInstance.GithubClient, _ = createGithubClient()
23+
}
3124

25+
if githubInstance == nil {
26+
lock.Lock()
27+
if githubInstance == nil || githubInstance.GithubClient == nil {
28+
err := createGithubClient()
29+
if err != nil {
30+
fmt.Println(err)
31+
}
3232
}
33+
defer lock.Unlock()
3334
}
3435

3536
return githubInstance
3637
}
3738

38-
func createGithubClient() (*github.Client, error) {
39-
ctx := context.Background()
39+
func createGithubClient() error {
40+
fmt.Println("Creating github instance now.")
41+
githubInstance = &GithubClientSingleton{}
4042

43+
ctx := context.Background()
44+
githubAPIKey := GetEnvVariable("GITHUB_TOKEN")
4145
if githubAPIKey != "" {
4246
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: githubAPIKey})
4347
tc := oauth2.NewClient(ctx, ts)
44-
return github.NewClient(tc), nil
48+
githubInstance.GithubClient = github.NewClient(tc)
4549
} else {
46-
return github.NewClient(nil), nil
50+
githubInstance.GithubClient = github.NewClient(nil)
4751
}
52+
53+
return nil
4854
}
4955

50-
func GetGithubUser(ctx context.Context, username string) (*github.User, error) {
56+
func GetGithubUser(ctx context.Context, username string, force bool) (*github.User, error) {
5157
// Fetch user profile
52-
user, _, err := GetGithubClientInstance().GithubClient.Users.Get(ctx, username)
58+
user, _, err := GetGithubClientInstance(force).GithubClient.Users.Get(ctx, username)
5359
if err != nil {
5460
if rateLimitErr, ok := err.(*github.RateLimitError); ok {
55-
return nil, fmt.Errorf("GitHub API rate limit exceeded: %v", rateLimitErr.Message)
61+
return nil, fmt.Errorf("429: %v", rateLimitErr.Message)
5662
}
5763
return nil, err
5864
}
@@ -61,19 +67,19 @@ func GetGithubUser(ctx context.Context, username string) (*github.User, error) {
6167

6268
func GetRepos(ctx context.Context, username string) ([]*github.Repository, error) {
6369
// Fetch repositories contributed to by the user
64-
repos, _, err := GetGithubClientInstance().GithubClient.Repositories.List(ctx, username, &github.RepositoryListOptions{
70+
repos, _, err := GetGithubClientInstance(false).GithubClient.Repositories.List(ctx, username, &github.RepositoryListOptions{
6571
Sort: "updated",
6672
})
6773
if err != nil {
68-
return nil, fmt.Errorf("failed to fetch repositories: %v", err)
74+
return nil, err
6975
}
7076
return repos, nil
7177
}
7278

7379
func GetCommits(ctx context.Context, repo *github.Repository, opts *github.CommitsListOptions) ([]*github.RepositoryCommit, *github.Response, error) {
74-
commits, resp, err := GetGithubClientInstance().GithubClient.Repositories.ListCommits(ctx, *repo.Owner.Login, *repo.Name, opts)
80+
commits, resp, err := GetGithubClientInstance(false).GithubClient.Repositories.ListCommits(ctx, *repo.Owner.Login, *repo.Name, opts)
7581
if err != nil {
76-
return nil, resp, fmt.Errorf("failed to fetch commits: %v", err)
82+
return nil, resp, err
7783
}
7884
return commits, resp, nil
7985
}

helper/helper.go

+22
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,28 @@ func GetEnvVariable(key string) string {
2323
return os.Getenv(key)
2424
}
2525

26+
func SetEnvVariable(key string, value string) error {
27+
err := godotenv.Load()
28+
if err != nil {
29+
log.Fatal("Error loading .env file")
30+
}
31+
return os.Setenv(key, value)
32+
}
33+
34+
func GetStringValue(s *string) string {
35+
if s != nil {
36+
return *s
37+
}
38+
return ""
39+
}
40+
41+
func GetIntValue(i *int) int {
42+
if i != nil {
43+
return *i
44+
}
45+
return 0
46+
}
47+
2648
func PopulateGitHubUser(recordRetrieved *xata.Record) (*views.GitHubUser, error) {
2749
user := &views.GitHubUser{}
2850
userValue := reflect.ValueOf(user).Elem()

helper/xata-helper.go

+22-9
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,28 @@ type RecordsClientSingleton struct {
2424
url string
2525
}
2626

27-
var singleInstance *RecordsClientSingleton
27+
var recordsClientInstance *RecordsClientSingleton
2828
var lock = &sync.Mutex{}
2929

3030
func GetRecordsClientInstance() *RecordsClientSingleton {
31-
if singleInstance == nil {
31+
if recordsClientInstance == nil {
3232
lock.Lock()
3333
defer lock.Unlock()
34-
if singleInstance == nil {
35-
fmt.Println("Creating single instance now.")
36-
singleInstance = &RecordsClientSingleton{
34+
if recordsClientInstance == nil {
35+
fmt.Println("Creating xata instance now.")
36+
recordsClientInstance = &RecordsClientSingleton{
3737
apiKey: xataAPIKey,
3838
DatabaseName: databaseName,
3939
TableName: tableName,
4040
url: xataURL,
4141
}
4242

43-
singleInstance.RecordsClient, _ = createRecordsClient()
43+
recordsClientInstance.RecordsClient, _ = createRecordsClient()
4444

4545
}
4646
}
4747

48-
return singleInstance
48+
return recordsClientInstance
4949
}
5050

5151
func createRecordsClient() (xata.RecordsClient, error) {
@@ -64,15 +64,28 @@ func GetRecordFromXata(ctx context.Context, id string) (*xata.Record, error) {
6464
},
6565
RecordID: id,
6666
}
67-
return GetRecordsClientInstance().RecordsClient.Get(ctx, getRecordRequest)
67+
68+
recordClient := GetRecordsClientInstance().RecordsClient
69+
if recordClient == nil {
70+
return nil, fmt.Errorf("RecordsClient instance is nil")
71+
}
72+
record, err := recordClient.Get(ctx, getRecordRequest)
73+
if err != nil {
74+
return nil, fmt.Errorf("failed to get record: %v", err)
75+
}
76+
return record, nil
6877
}
6978

7079
func SetRecordInXata(ctx context.Context, record *views.GitHubUser) (xata.Record, error) {
7180

7281
insertRecordRequest := GenerateInsertRecordRequest(record)
7382
insertRecordRequest.Body["CommitHistory"] = ToXataValue(record.CommitHistory) // Add CommitHistory to request
7483

75-
createdRecord, err := GetRecordsClientInstance().RecordsClient.InsertWithID(ctx, insertRecordRequest)
84+
recordClient := GetRecordsClientInstance().RecordsClient
85+
if recordClient == nil {
86+
return xata.Record{}, fmt.Errorf("RecordsClient instance is nil")
87+
}
88+
createdRecord, err := recordClient.InsertWithID(ctx, insertRecordRequest)
7689

7790
if err != nil {
7891
return *createdRecord, fmt.Errorf("failed to insert record: %v", err)

0 commit comments

Comments
 (0)