not tested
This commit is contained in:
parent
8b3aad50b0
commit
2a566ae019
BIN
cmd/go-jsonapi-example/go-jsonapi-example.exe
Normal file
BIN
cmd/go-jsonapi-example/go-jsonapi-example.exe
Normal file
Binary file not shown.
@ -17,20 +17,51 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"go-jsonapi-example/internal/model"
|
||||
"go-jsonapi-example/internal/resource"
|
||||
"go-jsonapi-example/internal/storage"
|
||||
|
||||
"github.com/manyminds/api2go"
|
||||
|
||||
"github.com/juju/gnuflag"
|
||||
)
|
||||
|
||||
func main() {
|
||||
port := 8080
|
||||
baseURL := fmt.Sprintf("http://localhost:%d", port)
|
||||
api := api2go.NewAPIWithBaseURL("v1", baseURL)
|
||||
carStorage := storage.NewCarStorage()
|
||||
api.AddResource(model.Car{}, resource.CarResource{CarStorage: carStorage})
|
||||
host := gnuflag.String("host", "localhost", "host")
|
||||
port := gnuflag.Int("port", 8080, "port")
|
||||
gnuflag.Parse(true)
|
||||
|
||||
fmt.Printf("Listening on :%d", port)
|
||||
http.ListenAndServe(fmt.Sprintf(":%d", port), api.Handler())
|
||||
addr := fmt.Sprintf("%s:%d", *host, *port)
|
||||
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
1
go.mod
@ -4,5 +4,6 @@ go 1.14
|
||||
|
||||
require (
|
||||
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
|
||||
)
|
||||
|
2
go.sum
2
go.sum
@ -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/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/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/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
|
||||
|
@ -3,6 +3,9 @@ package model
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"net/http"
|
||||
|
||||
"github.com/manyminds/api2go"
|
||||
"github.com/manyminds/api2go/jsonapi"
|
||||
)
|
||||
|
||||
@ -10,47 +13,97 @@ type Car struct {
|
||||
ID string `json:"-"`
|
||||
Brand string `json:"brand"`
|
||||
Model string `json:"model"`
|
||||
Price uint `json:"price"`
|
||||
Status string `json:"status"`
|
||||
Price uint64 `json:"price"`
|
||||
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
|
||||
func (u Car) GetID() string {
|
||||
return u.ID
|
||||
func (c Car) GetID() string {
|
||||
return c.ID
|
||||
}
|
||||
|
||||
// SetID to satisfy jsonapi.UnmarshalIdentifier interface
|
||||
func (u *Car) SetID(id string) error {
|
||||
u.ID = id
|
||||
func (c *Car) SetID(id string) error {
|
||||
c.ID = id
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetReferences to satisfy the jsonapi.MarshalReferences interface
|
||||
func (u Car) GetReferences() []jsonapi.Reference {
|
||||
func (c Car) GetReferences() []jsonapi.Reference {
|
||||
return []jsonapi.Reference{}
|
||||
}
|
||||
|
||||
// GetReferencedIDs to satisfy the jsonapi.MarshalLinkedRelations interface
|
||||
func (u Car) GetReferencedIDs() []jsonapi.ReferenceID {
|
||||
func (c Car) GetReferencedIDs() []jsonapi.ReferenceID {
|
||||
return []jsonapi.ReferenceID{}
|
||||
}
|
||||
|
||||
// GetReferencedStructs to satisfy the jsonapi.MarhsalIncludedRelations interface
|
||||
func (u Car) GetReferencedStructs() []jsonapi.MarshalIdentifier {
|
||||
func (c Car) GetReferencedStructs() []jsonapi.MarshalIdentifier {
|
||||
return []jsonapi.MarshalIdentifier{}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
if ok, httpErr := car.Verify(); !ok {
|
||||
return &Response{}, httpErr
|
||||
}
|
||||
|
||||
id := s.CarStorage.Insert(car)
|
||||
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)
|
||||
}
|
||||
|
||||
if ok, httpErr := car.Verify(); !ok {
|
||||
return &Response{}, httpErr
|
||||
}
|
||||
|
||||
err := s.CarStorage.Update(car)
|
||||
return &Response{Res: car, Code: http.StatusNoContent}, err
|
||||
return &Response{Code: http.StatusOK}, err
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ type Response struct {
|
||||
func (r Response) Metadata() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"author": "GenZmeY",
|
||||
"license": "wtfpl",
|
||||
"license-url": "http://www.wtfpl.net",
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user