not tested

This commit is contained in:
GenZmeY 2021-03-19 20:24:02 +03:00
parent 8b3aad50b0
commit 2a566ae019
8 changed files with 119 additions and 23 deletions

View File

@ -21,3 +21,6 @@ check-build:
clean: clean:
rm -rf $(BINDIR) rm -rf $(BINDIR)
run: check-build
$(BIN)

Binary file not shown.

View File

@ -17,20 +17,51 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"context"
"os"
"os/signal"
"syscall"
"go-jsonapi-example/internal/model" "go-jsonapi-example/internal/model"
"go-jsonapi-example/internal/resource" "go-jsonapi-example/internal/resource"
"go-jsonapi-example/internal/storage" "go-jsonapi-example/internal/storage"
"github.com/manyminds/api2go" "github.com/manyminds/api2go"
"github.com/juju/gnuflag"
) )
func main() { func main() {
port := 8080 host := gnuflag.String("host", "localhost", "host")
baseURL := fmt.Sprintf("http://localhost:%d", port) port := gnuflag.Int("port", 8080, "port")
api := api2go.NewAPIWithBaseURL("v1", baseURL) gnuflag.Parse(true)
carStorage := storage.NewCarStorage()
api.AddResource(model.Car{}, resource.CarResource{CarStorage: carStorage})
fmt.Printf("Listening on :%d", port) addr := fmt.Sprintf("%s:%d", *host, *port)
http.ListenAndServe(fmt.Sprintf(":%d", port), api.Handler()) baseURL := fmt.Sprintf("http://%s", addr)
api := api2go.NewAPIWithBaseURL("v1", baseURL)
api.AddResource(model.Car{}, resource.CarResource{CarStorage: storage.NewCarStorage()})
server := &http.Server{Addr: addr, Handler: api.Handler()}
closeHandler(server)
fmt.Printf("Listening on %s\n", addr)
if err := server.ListenAndServe(); err != http.ErrServerClosed {
fmt.Printf("error: %s\n", err)
os.Exit(1)
} else {
fmt.Println(err)
os.Exit(0)
}
}
func closeHandler(server *http.Server) {
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
go func() {
<-interrupt
if err := server.Shutdown(context.Background()); err != nil {
fmt.Printf("error: %s\n", err)
}
}()
} }

1
go.mod
View File

@ -4,5 +4,6 @@ go 1.14
require ( require (
github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/mux v1.8.0 // indirect
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d
github.com/manyminds/api2go v0.0.0-20210211132652-5457038544fa github.com/manyminds/api2go v0.0.0-20210211132652-5457038544fa
) )

2
go.sum
View File

@ -28,6 +28,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d h1:c93kUJDtVAXFEhsCh5jSxyOJmFHuzcihnslQiX8Urwo=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg= github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=

View File

@ -3,6 +3,9 @@ package model
import ( import (
"errors" "errors"
"net/http"
"github.com/manyminds/api2go"
"github.com/manyminds/api2go/jsonapi" "github.com/manyminds/api2go/jsonapi"
) )
@ -10,47 +13,97 @@ type Car struct {
ID string `json:"-"` ID string `json:"-"`
Brand string `json:"brand"` Brand string `json:"brand"`
Model string `json:"model"` Model string `json:"model"`
Price uint `json:"price"` Price uint64 `json:"price"`
Status string `json:"status"` Status string `json:"status"` // OnTheWay, InStock, Sold, Discontinued
}
func (c Car) Verify() (bool, api2go.HTTPError) {
var verifyErrors []api2go.Error
var httpError api2go.HTTPError
if c.Brand == "" {
newErr := newVerifyError(
"Invalid Attribute",
"attribute cannot be empty",
"/data/attributes/brand")
verifyErrors = append(verifyErrors, newErr)
}
if c.Model == "" {
newErr := newVerifyError(
"Invalid Attribute",
"attribute cannot be empty",
"/data/attributes/model")
verifyErrors = append(verifyErrors, newErr)
}
if c.Status != "OnTheWay" &&
c.Status != "InStock" &&
c.Status != "Sold" &&
c.Status != "Discontinued" {
newErr := newVerifyError(
"Invalid Attribute",
"attribute must be one of: OnTheWay, InStock, Sold, Discontinued",
"/data/attributes/brand")
verifyErrors = append(verifyErrors, newErr)
}
ok := len(verifyErrors) == 0
if !ok {
httpError := api2go.NewHTTPError(
errors.New("Invalid content"),
"Invalid content",
http.StatusBadRequest)
httpError.Errors = verifyErrors
}
return ok, httpError
}
func newVerifyError(title string, detail string, pointer string) api2go.Error {
var newError api2go.Error
newError.Title = title
newError.Detail = detail
newError.Source = &api2go.ErrorSource{Pointer: pointer}
return newError
} }
// GetID to satisfy jsonapi.MarshalIdentifier interface // GetID to satisfy jsonapi.MarshalIdentifier interface
func (u Car) GetID() string { func (c Car) GetID() string {
return u.ID return c.ID
} }
// SetID to satisfy jsonapi.UnmarshalIdentifier interface // SetID to satisfy jsonapi.UnmarshalIdentifier interface
func (u *Car) SetID(id string) error { func (c *Car) SetID(id string) error {
u.ID = id c.ID = id
return nil return nil
} }
// GetReferences to satisfy the jsonapi.MarshalReferences interface // GetReferences to satisfy the jsonapi.MarshalReferences interface
func (u Car) GetReferences() []jsonapi.Reference { func (c Car) GetReferences() []jsonapi.Reference {
return []jsonapi.Reference{} return []jsonapi.Reference{}
} }
// GetReferencedIDs to satisfy the jsonapi.MarshalLinkedRelations interface // GetReferencedIDs to satisfy the jsonapi.MarshalLinkedRelations interface
func (u Car) GetReferencedIDs() []jsonapi.ReferenceID { func (c Car) GetReferencedIDs() []jsonapi.ReferenceID {
return []jsonapi.ReferenceID{} return []jsonapi.ReferenceID{}
} }
// GetReferencedStructs to satisfy the jsonapi.MarhsalIncludedRelations interface // GetReferencedStructs to satisfy the jsonapi.MarhsalIncludedRelations interface
func (u Car) GetReferencedStructs() []jsonapi.MarshalIdentifier { func (c Car) GetReferencedStructs() []jsonapi.MarshalIdentifier {
return []jsonapi.MarshalIdentifier{} return []jsonapi.MarshalIdentifier{}
} }
// SetToManyReferenceIDs sets the sweets reference IDs and satisfies the jsonapi.UnmarshalToManyRelations interface // SetToManyReferenceIDs sets the sweets reference IDs and satisfies the jsonapi.UnmarshalToManyRelations interface
func (u *Car) SetToManyReferenceIDs(name string, IDs []string) error { func (c *Car) SetToManyReferenceIDs(name string, IDs []string) error {
return errors.New("There is no to-many relationship with the name " + name) return errors.New("There is no to-many relationship with the name " + name)
} }
// AddToManyIDs adds some new sweets that a users loves so much // AddToManyIDs adds some new sweets that a users loves so much
func (u *Car) AddToManyIDs(name string, IDs []string) error { func (c *Car) AddToManyIDs(name string, IDs []string) error {
return errors.New("There is no to-many relationship with the name " + name) return errors.New("There is no to-many relationship with the name " + name)
} }
// DeleteToManyIDs removes some sweets from a users because they made him very sick // DeleteToManyIDs removes some sweets from a users because they made him very sick
func (u *Car) DeleteToManyIDs(name string, IDs []string) error { func (c *Car) DeleteToManyIDs(name string, IDs []string) error {
return errors.New("There is no to-many relationship with the name " + name) return errors.New("There is no to-many relationship with the name " + name)
} }

View File

@ -122,6 +122,10 @@ func (s CarResource) Create(obj interface{}, r api2go.Request) (api2go.Responder
return &Response{}, api2go.NewHTTPError(errors.New("Invalid instance given"), "Invalid instance given", http.StatusBadRequest) return &Response{}, api2go.NewHTTPError(errors.New("Invalid instance given"), "Invalid instance given", http.StatusBadRequest)
} }
if ok, httpErr := car.Verify(); !ok {
return &Response{}, httpErr
}
id := s.CarStorage.Insert(car) id := s.CarStorage.Insert(car)
car.ID = id car.ID = id
@ -141,6 +145,10 @@ func (s CarResource) Update(obj interface{}, r api2go.Request) (api2go.Responder
return &Response{}, api2go.NewHTTPError(errors.New("Invalid instance given"), "Invalid instance given", http.StatusBadRequest) return &Response{}, api2go.NewHTTPError(errors.New("Invalid instance given"), "Invalid instance given", http.StatusBadRequest)
} }
if ok, httpErr := car.Verify(); !ok {
return &Response{}, httpErr
}
err := s.CarStorage.Update(car) err := s.CarStorage.Update(car)
return &Response{Res: car, Code: http.StatusNoContent}, err return &Response{Code: http.StatusOK}, err
} }

View File

@ -8,9 +8,7 @@ type Response struct {
func (r Response) Metadata() map[string]interface{} { func (r Response) Metadata() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
"author": "GenZmeY", "author": "GenZmeY",
"license": "wtfpl",
"license-url": "http://www.wtfpl.net",
} }
} }