-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added some helpful default behavior and types (#3)
- Loading branch information
Showing
21 changed files
with
291 additions
and
52 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
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
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
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
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,31 @@ | ||
package httpwrap | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
) | ||
|
||
// HTTPError implements both the HTTPResponse interface and the standard error | ||
// interface. | ||
type HTTPError struct { | ||
code int | ||
body string | ||
} | ||
|
||
func NewHTTPError(code int, format string, args ...any) HTTPError { | ||
return HTTPError{ | ||
code: code, | ||
body: fmt.Sprintf(format, args...), | ||
} | ||
} | ||
|
||
func (err HTTPError) Error() string { | ||
return fmt.Sprintf("http error: %d: %s", err.code, err.body) | ||
} | ||
|
||
func (err HTTPError) StatusCode() int { return err.code } | ||
|
||
func (err HTTPError) WriteBody(writer io.Writer) error { | ||
_, writeError := io.WriteString(writer, err.body) | ||
return writeError | ||
} |
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,143 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
"net/http" | ||
|
||
"github.com/apourchet/httpwrap" | ||
"github.com/gorilla/mux" | ||
) | ||
|
||
// ***** Type Definitions ***** | ||
type APICredentials struct { | ||
Key string `http:"header=X-PETSTORE-KEY"` | ||
} | ||
|
||
type PetStoreHandler struct { | ||
pets map[string]*Pet | ||
} | ||
|
||
type Pet struct { | ||
Name string `json:"name"` | ||
Category int `json:"category"` | ||
PhotoURLs []string `json:"photoUrls"` | ||
} | ||
|
||
func (pet Pet) IsInCategories(categories []int) bool { | ||
for _, c := range categories { | ||
if pet.Category == c { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
var ErrBadAPICreds = httpwrap.NewHTTPError(http.StatusUnauthorized, "bad API credentials") | ||
var ErrPetConflict = httpwrap.NewHTTPError(http.StatusConflict, "duplicate pet") | ||
var ErrPetNotFound = httpwrap.NewHTTPError(http.StatusNotFound, "pet not found") | ||
|
||
// ***** Middleware Definitions ***** | ||
// checkAPICreds checks the api credentials passed into the request. | ||
func checkAPICreds(creds APICredentials) error { | ||
if creds.Key == "my-secret-key" { | ||
return nil | ||
} | ||
return ErrBadAPICreds | ||
} | ||
|
||
// ***** Handler Methods ***** | ||
// AddPet adds a new pet to the store. | ||
func (h *PetStoreHandler) AddPet(pet Pet) error { | ||
if _, found := h.pets[pet.Name]; found { | ||
return ErrPetConflict | ||
} | ||
h.pets[pet.Name] = &pet | ||
return nil | ||
} | ||
|
||
// GetPets returns the list of pets in the store. | ||
func (h *PetStoreHandler) GetPets() (res []Pet, err error) { | ||
res = make([]Pet, 0, len(h.pets)) | ||
for _, pet := range h.pets { | ||
res = append(res, *pet) | ||
} | ||
return res, nil | ||
} | ||
|
||
type GetByNameParams struct { | ||
Name string `http:"segment=name"` | ||
} | ||
|
||
// GetPetByName returns a pet given its name. | ||
func (h *PetStoreHandler) GetPetByName(params GetByNameParams) (pet *Pet, err error) { | ||
pet, found := h.pets[params.Name] | ||
if !found { | ||
return nil, ErrPetNotFound | ||
} | ||
return pet, nil | ||
} | ||
|
||
type UpdateParams struct { | ||
Name string `http:"segment=name"` | ||
|
||
Category *int `json:"category"` | ||
PhotoURLs *[]string `json:"photoUrls"` | ||
} | ||
|
||
// UpdatePet updates a pet given its name. | ||
func (h *PetStoreHandler) UpdatePet(params UpdateParams) error { | ||
pet, found := h.pets[params.Name] | ||
if !found { | ||
return ErrPetNotFound | ||
} | ||
|
||
if params.Category != nil { | ||
pet.Category = *params.Category | ||
} | ||
if params.PhotoURLs != nil { | ||
pet.PhotoURLs = *params.PhotoURLs | ||
} | ||
return nil | ||
} | ||
|
||
type FilterPetParams struct { | ||
Categories *[]int `http:"query=categories"` | ||
HasPhotos *bool `http:"query=hasPhotos"` | ||
} | ||
|
||
// FilterPets returns a list of pets that match the parameters given. | ||
func (h *PetStoreHandler) FilterPets(params FilterPetParams) []Pet { | ||
res := []Pet{} | ||
for _, pet := range h.pets { | ||
if params.HasPhotos != nil && len(pet.PhotoURLs) == 0 { | ||
continue | ||
} else if params.Categories != nil && !pet.IsInCategories(*params.Categories) { | ||
continue | ||
} | ||
res = append(res, *pet) | ||
} | ||
return res | ||
} | ||
|
||
func (h *PetStoreHandler) ClearStore() error { | ||
h.pets = map[string]*Pet{} | ||
return nil | ||
} | ||
|
||
func main() { | ||
router := mux.NewRouter() | ||
|
||
handler := &PetStoreHandler{pets: map[string]*Pet{}} | ||
wrapper := httpwrap.NewStandardWrapper().Before(checkAPICreds) | ||
|
||
router.Handle("/pets", wrapper.Wrap(handler.AddPet)).Methods("POST") | ||
router.Handle("/pets", wrapper.Wrap(handler.GetPets)).Methods("GET") | ||
router.Handle("/pets/filtered", wrapper.Wrap(handler.FilterPets)).Methods("GET") | ||
router.Handle("/pets/{name}", wrapper.Wrap(handler.GetPetByName)).Methods("GET") | ||
router.Handle("/pets/{name}", wrapper.Wrap(handler.UpdatePet)).Methods("PUT") | ||
|
||
router.Handle("/clear", wrapper.Wrap(handler.ClearStore)).Methods("POST") | ||
|
||
http.Handle("/", router) | ||
log.Fatal(http.ListenAndServe(":3000", router)) | ||
} |
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,8 +1,13 @@ | ||
module github.com/apourchet/httpwrap | ||
|
||
go 1.12 | ||
go 1.20 | ||
|
||
require ( | ||
github.com/gorilla/mux v1.7.2 | ||
github.com/stretchr/testify v1.3.0 | ||
) | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.0 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
) |
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
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
Oops, something went wrong.