Skip to content

Commit

Permalink
Add structs for graphql reponses to keep thing a bit more structured …
Browse files Browse the repository at this point in the history
…(lol). Fix issue with badges filter being null and showing an error. (#15)
  • Loading branch information
meruff authored Jul 23, 2022
1 parent a6e6f80 commit fed6a47
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 9 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A [Golang](https://go.dev) app that runs on [Heroku](https://heroku.com) to make

> 🚨 Note: In order to retrieve data for a specific Trailhead User, they must have their profile set to public.
Trailhead changes their services occasionally so this an break at any time!
Trailhead changes their services occasionally so this can break at any time!

## Installation

Expand Down
30 changes: 23 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,13 @@ func skillsHandler(w http.ResponseWriter, r *http.Request) {
"trailblazerId": "%s"
}`, userID))

var trailheadSkillsData trailhead.Skills
json.Unmarshal([]byte(responseBody), &trailheadSkillsData)

if err != nil {
writeErrorToBrowser(w, `{"error":"No data returned from Trailhead."}`, 503)
} else {
writeJSONToBrowser(w, responseBody)
} else if trailheadSkillsData.Profile.EarnedSkills != nil {
encodeAndWriteToBrowser(w, trailheadSkillsData)
}
}

Expand All @@ -140,10 +143,13 @@ func rankHandler(w http.ResponseWriter, r *http.Request) {
"trailblazerId": "%s"
}`, userID))

var trailheadRankData trailhead.Rank
json.Unmarshal([]byte(responseBody), &trailheadRankData)

if err != nil {
writeErrorToBrowser(w, `{"error":"No data returned from Trailhead."}`, 503)
} else {
writeJSONToBrowser(w, responseBody)
} else if trailheadRankData.Profile.TrailheadStats.Typename != "" {
encodeAndWriteToBrowser(w, trailheadRankData)
}
}

Expand All @@ -168,8 +174,9 @@ func badgesHandler(w http.ResponseWriter, r *http.Request) {
if contains(getValidBadgeFilters(), filter) {
var upperFilter = strings.ToUpper(filter)
badgeRequestStruct.Filter = &upperFilter
} else if filter != "all" {
} else if filter != "all" && filter != "" {
writeErrorToBrowser(w, `{"error":"Expected badge filter to be one of: MODULE, PROJECT, SUPERBADGE, EVENT, STANDALONE."}`, 501)
return
}

// Set count
Expand All @@ -187,10 +194,13 @@ func badgesHandler(w http.ResponseWriter, r *http.Request) {
badgeRequestBody, err := json.Marshal(badgeRequestStruct)
responseBody, err := doSupabaseCallout(badgesUrl, string(badgeRequestBody))

var trailheadBadgeData trailhead.Badges
json.Unmarshal([]byte(responseBody), &trailheadBadgeData)

if err != nil {
writeErrorToBrowser(w, `{"error":"No data returned from Trailhead."}`, 503)
} else {
writeJSONToBrowser(w, responseBody)
} else if trailheadBadgeData.Profile.EarnedAwards.Edges != nil {
encodeAndWriteToBrowser(w, trailheadBadgeData)
}
}

Expand Down Expand Up @@ -435,6 +445,12 @@ func writeErrorToBrowser(w http.ResponseWriter, err string, code int) {
w.Write([]byte(err))
}

// encodeAndWriteToBrowser encodes a given interface and writes it to the browser as JSON.
func encodeAndWriteToBrowser(w http.ResponseWriter, i interface{}) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(i)
}

// contains simply checks if a string exists inside a slice.
func contains(s []string, str string) bool {
for _, v := range s {
Expand Down
78 changes: 77 additions & 1 deletion trailhead/trailhead.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package trailhead

import "strings"

// Data represent a response from trailhead.salesforce.com
// Data represents a response from trailhead.
type Data struct {
Actions []struct {
ID string `json:"id"`
Expand Down Expand Up @@ -35,6 +35,82 @@ type Data struct {
} `json:"context"`
}

// Rank represents skill data returned from trailhead.
type Rank struct {
Profile struct {
Typename string `json:"__typename"`
TrailheadStats struct {
Typename string `json:"__typename"`
EarnedPointsSum int `json:"earnedPointsSum"`
EarnedBadgesCount int `json:"earnedBadgesCount"`
CompletedTrailCount int `json:"completedTrailCount"`
Rank struct {
Typename string `json:"__typename"`
Title string `json:"title"`
RequiredPointsSum int `json:"requiredPointsSum"`
RequiredBadgesCount int `json:"requiredBadgesCount"`
ImageURL string `json:"imageUrl"`
} `json:"rank"`
NextRank interface{} `json:"nextRank"`
} `json:"trailheadStats"`
} `json:"profile"`
}

// Skills represents skill data returned from trailhead.
type Skills struct {
Profile struct {
Typename string `json:"__typename"`
EarnedSkills []struct {
Typename string `json:"__typename"`
EarnedPointsSum int `json:"earnedPointsSum"`
ID string `json:"id"`
ItemProgressEntryCount int `json:"itemProgressEntryCount"`
Skill struct {
Typename string `json:"__typename"`
APIName string `json:"apiName"`
ID string `json:"id"`
Name string `json:"name"`
} `json:"skill"`
} `json:"earnedSkills"`
} `json:"profile"`
}

// Badges represents skill data returned from trailhead.
type Badges struct {
Profile struct {
Typename string `json:"__typename"`
EarnedAwards struct {
Edges []struct {
Node struct {
Typename string `json:"__typename"`
ID string `json:"id"`
Award struct {
Typename string `json:"__typename"`
ID string `json:"id"`
Title string `json:"title"`
Type string `json:"type"`
Icon string `json:"icon"`
Content struct {
Typename string `json:"__typename"`
WebURL string `json:"webUrl"`
Description string `json:"description"`
} `json:"content"`
} `json:"award"`
EarnedAt string `json:"earnedAt"`
EarnedPointsSum string `json:"earnedPointsSum"`
} `json:"node"`
} `json:"edges"`
PageInfo struct {
Typename string `json:"__typename"`
EndCursor string `json:"endCursor"`
HasNextPage bool `json:"hasNextPage"`
StartCursor string `json:"startCursor"`
HasPreviousPage bool `json:"hasPreviousPage"`
} `json:"pageInfo"`
} `json:"earnedAwards"`
} `json:"profile"`
}

// ProfileAppConfig represents the full configuration for the Salesforce Trailhead profile app
type ProfileAppConfig struct {
AuraConfig struct {
Expand Down

0 comments on commit fed6a47

Please sign in to comment.