-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
240 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[] |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
module creatorlink/api | ||
module creatorlink | ||
|
||
go 1.23.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package handlers | ||
|
||
import ( | ||
"encoding/json" | ||
"net/http" | ||
"creatorlink/types" | ||
) | ||
|
||
type CreatorHandler struct { | ||
creatorService types.CreatorService | ||
} | ||
|
||
func NewCreatorHandler(creatorService types.CreatorService) *CreatorHandler { | ||
return &CreatorHandler{ | ||
creatorService: creatorService, | ||
} | ||
} | ||
|
||
func (h *CreatorHandler) HandleGetCreator(w http.ResponseWriter, r *http.Request) { | ||
creatorID := r.PathValue("creatorID") | ||
continent := r.PathValue("continent") | ||
|
||
creator, err := h.creatorService.GetCreator(continent, creatorID) | ||
if err != nil { | ||
sendErrorResponse(w, err.Error(), http.StatusNotFound) | ||
return | ||
} | ||
|
||
sendSuccessResponse(w, creator) | ||
} | ||
|
||
func sendSuccessResponse(w http.ResponseWriter, data interface{}) { | ||
response := types.APIResponse{ | ||
Status: "success", | ||
Data: data, | ||
} | ||
w.Header().Set("Content-Type", "application/json") | ||
json.NewEncoder(w).Encode(response) | ||
} | ||
|
||
func sendErrorResponse(w http.ResponseWriter, message string, statusCode int) { | ||
response := types.APIResponse{ | ||
Status: "error", | ||
Message: message, | ||
} | ||
w.Header().Set("Content-Type", "application/json") | ||
w.WriteHeader(statusCode) | ||
json.NewEncoder(w).Encode(response) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package routes | ||
|
||
import ( | ||
"net/http" | ||
"creatorlink/handlers" | ||
"creatorlink/services" | ||
) | ||
|
||
func RegisterRoutes(router *http.ServeMux, creatorService *services.CreatorService) { | ||
creatorHandler := handlers.NewCreatorHandler(creatorService) | ||
|
||
router.HandleFunc("GET /{continent}/creator/{creatorID}", creatorHandler.HandleGetCreator) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
"net/http" | ||
"creatorlink/routes" | ||
"creatorlink/services" | ||
) | ||
|
||
type APIServer struct { | ||
port string | ||
dataPath string | ||
} | ||
|
||
func NewAPIServer(port string, dataPath string) *APIServer { | ||
return &APIServer{ | ||
port: port, | ||
dataPath: dataPath, | ||
} | ||
} | ||
|
||
func (s *APIServer) Run() error { | ||
router := http.NewServeMux() | ||
|
||
// Initialize services | ||
creatorService := services.NewCreatorService(s.dataPath) | ||
|
||
// Register routes | ||
routes.RegisterRoutes(router, creatorService) | ||
|
||
v1 := http.NewServeMux() | ||
v1.Handle("/api/v1/", http.StripPrefix("/api/v1", router)) | ||
|
||
server := http.Server{ | ||
Addr: s.port, | ||
Handler: v1, | ||
} | ||
|
||
log.Printf("Server has started on %s", s.port) | ||
return server.ListenAndServe() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package services | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io/fs" | ||
"os" | ||
"path/filepath" | ||
"creatorlink/types" | ||
) | ||
|
||
type CreatorService struct { | ||
dataPath string | ||
} | ||
|
||
func NewCreatorService(dataPath string) *CreatorService { | ||
return &CreatorService{ | ||
dataPath: dataPath, | ||
} | ||
} | ||
|
||
func (s *CreatorService) GetCreator(continent, creatorID string) (types.Creator, error) { | ||
if continent == "worldwide" { | ||
return s.searchAllContinents(creatorID) | ||
} | ||
|
||
return s.searchSingleContinent(continent, creatorID) | ||
} | ||
|
||
func (s *CreatorService) searchSingleContinent(continent, creatorID string) (types.Creator, error) { | ||
filePath := filepath.Join(s.dataPath, fmt.Sprintf("%s.json", continent)) | ||
creators, err := s.loadCreators(filePath) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to load creators data for %s: %v", continent, err) | ||
} | ||
|
||
creator, found := s.findCreator(creators, creatorID) | ||
if !found { | ||
return nil, fmt.Errorf("creator not found in %s", continent) | ||
} | ||
|
||
return creator, nil | ||
} | ||
|
||
func (s *CreatorService) searchAllContinents(creatorID string) (types.Creator, error) { | ||
var searchErrors []string | ||
|
||
err := filepath.WalkDir(s.dataPath, func(path string, d fs.DirEntry, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if d.IsDir() || filepath.Ext(path) != ".json" { | ||
return nil | ||
} | ||
|
||
creators, err := s.loadCreators(path) | ||
if err != nil { | ||
searchErrors = append(searchErrors, fmt.Sprintf("error loading %s: %v", path, err)) | ||
return nil | ||
} | ||
|
||
if creator, found := s.findCreator(creators, creatorID); found { | ||
return &foundCreator{creator: creator} | ||
} | ||
|
||
return nil | ||
}) | ||
|
||
if err != nil { | ||
if ferr, ok := err.(*foundCreator); ok { | ||
return ferr.creator, nil | ||
} | ||
return nil, fmt.Errorf("error searching creators: %v", err) | ||
} | ||
|
||
if len(searchErrors) > 0 { | ||
return nil, fmt.Errorf("some errors occurred while searching: %v", searchErrors) | ||
} | ||
|
||
return nil, fmt.Errorf("creator not found in any continent") | ||
} | ||
|
||
func (s *CreatorService) loadCreators(filePath string) ([]types.Creator, error) { | ||
fileContent, err := os.ReadFile(filePath) | ||
if err != nil { | ||
return nil, fmt.Errorf("error reading file: %v", err) | ||
} | ||
|
||
var creators []types.Creator | ||
err = json.Unmarshal(fileContent, &creators) | ||
if err != nil { | ||
return nil, fmt.Errorf("error unmarshalling JSON: %v", err) | ||
} | ||
|
||
return creators, nil | ||
} | ||
|
||
func (s *CreatorService) findCreator(creators []types.Creator, creatorID string) (types.Creator, bool) { | ||
for _, creator := range creators { | ||
if _, ok := creator[creatorID]; ok { | ||
return creator, true | ||
} | ||
} | ||
return nil, false | ||
} | ||
|
||
// Custom error type to handle found creator | ||
type foundCreator struct { | ||
creator types.Creator | ||
} | ||
|
||
func (e *foundCreator) Error() string { | ||
return "creator found" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package types | ||
|
||
type Creator map[string]interface{} | ||
|
||
type APIResponse struct { | ||
Status string `json:"status"` | ||
Data interface{} `json:"data,omitempty"` | ||
Message string `json:"message,omitempty"` | ||
} | ||
|
||
type CreatorService interface { | ||
GetCreator(continent, creatorID string) (Creator, error) | ||
} |