Skip to content

Introduce LocalID and update go.mod dependencies to the latest #352

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ '1.17', '1.15', '1.14', '1.13' ]
go: [ '1.18', '1.19', '1.20' ]
name: Go ${{ matrix.go }} tests
steps:
- uses: actions/checkout@v2
Expand All @@ -24,9 +24,12 @@ jobs:
run: |
go get -t -d -v ./...
go get github.com/onsi/ginkgo/ginkgo
go install github.com/onsi/ginkgo/ginkgo
go get -u golang.org/x/lint/golint
go get -u github.com/modocache/gover
go install github.com/modocache/gover
go get -u github.com/mattn/goveralls
go install github.com/mattn/goveralls
- name: Run tests
run: |
ginkgo -r -cover --randomizeAllSpecs --randomizeSuites --failOnPending --trace --race --progress
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
*.o
*.a
*.so
*.idea

# Folders
_obj
Expand Down
37 changes: 19 additions & 18 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,9 @@ func (api *API) addResource(prototype jsonapi.MarshalIdentifier, source interfac
name = resourceType.Elem().Name()
}

// check if EntityNamer interface is implemented and use that as name
entityName, ok := prototype.(jsonapi.EntityNamer)
if ok {
name = entityName.GetName()
identifier := prototype.GetID()
if identifier.Name != "" {
name = identifier.Name
} else {
name = jsonapi.Jsonify(jsonapi.Pluralize(name))
}
Expand Down Expand Up @@ -711,9 +710,9 @@ func (res *resource) handleCreate(c APIContexter, w http.ResponseWriter, r *http
}

if len(prefix) > 0 {
w.Header().Set("Location", "/"+prefix+"/"+res.name+"/"+result.GetID())
w.Header().Set("Location", "/"+prefix+"/"+res.name+"/"+result.GetID().ID)
} else {
w.Header().Set("Location", "/"+res.name+"/"+result.GetID())
w.Header().Set("Location", "/"+res.name+"/"+result.GetID().ID)
}

// handle 200 status codes
Expand Down Expand Up @@ -764,7 +763,7 @@ func (res *resource) handleUpdate(c APIContexter, w http.ResponseWriter, r *http
}

identifiable, ok := updatingObj.Interface().(jsonapi.MarshalIdentifier)
if !ok || identifiable.GetID() != id {
if !ok || identifiable.GetID().ID != id {
conflictError := errors.New("id in the resource does not match servers endpoint")
return NewHTTPError(conflictError, conflictError.Error(), http.StatusConflict)
}
Expand Down Expand Up @@ -1231,17 +1230,18 @@ func handleError(err error, w http.ResponseWriter, r *http.Request, contentType
func processRelationshipsData(data interface{}, linkName string, target interface{}) error {
hasOne, ok := data.(map[string]interface{})
if ok {
hasOneID, ok := hasOne["id"].(string)
if !ok {
return fmt.Errorf("data object must have a field id for %s", linkName)
hasOneID, okID := hasOne["id"].(string)
hasOneLID, okLID := hasOne["lid"].(string)
if !okID && !okLID {
return fmt.Errorf("data object must have a field id or lid for %s", linkName)
}

target, ok := target.(jsonapi.UnmarshalToOneRelations)
if !ok {
return errors.New("target struct must implement interface UnmarshalToOneRelations")
}

err := target.SetToOneReferenceID(linkName, hasOneID)
err := target.SetToOneReferenceID(linkName, &jsonapi.Identifier{ID: hasOneID, LID: hasOneLID})
if err != nil {
return err
}
Expand All @@ -1252,7 +1252,7 @@ func processRelationshipsData(data interface{}, linkName string, target interfac
return errors.New("target struct must implement interface UnmarshalToOneRelations")
}

err := target.SetToOneReferenceID(linkName, "")
err := target.SetToOneReferenceID(linkName, nil)
if err != nil {
return err
}
Expand All @@ -1267,22 +1267,23 @@ func processRelationshipsData(data interface{}, linkName string, target interfac
return errors.New("target struct must implement interface UnmarshalToManyRelations")
}

hasManyIDs := []string{}
hasManyRelations := make([]jsonapi.Identifier, 0, len(hasMany))

for _, entry := range hasMany {
data, ok := entry.(map[string]interface{})
if !ok {
return fmt.Errorf("entry in data array must be an object for %s", linkName)
}
dataID, ok := data["id"].(string)
if !ok {
return fmt.Errorf("all data objects must have a field id for %s", linkName)
dataID, okID := data["id"].(string)
dataLID, okLID := data["lid"].(string)
if !okID && !okLID {
return fmt.Errorf("all data objects must have a field id or lid for %s", linkName)
}

hasManyIDs = append(hasManyIDs, dataID)
hasManyRelations = append(hasManyRelations, jsonapi.Identifier{ID: dataID, LID: dataLID})
}

err := target.SetToManyReferenceIDs(linkName, hasManyIDs)
err := target.SetToManyReferenceIDs(linkName, hasManyRelations)
if err != nil {
return err
}
Expand Down
17 changes: 8 additions & 9 deletions api_entity_name_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package api2go

import (
"github.com/manyminds/api2go/jsonapi"
"net/http"
"net/http/httptest"
"strings"
Expand All @@ -11,22 +12,20 @@ import (

type BaguetteTaste struct {
ID string `json:"-"`
LID string `json:"-"`
Taste string `json:"taste"`
}

func (s BaguetteTaste) GetID() string {
return s.ID
func (s BaguetteTaste) GetID() jsonapi.Identifier {
return jsonapi.Identifier{ID: s.ID, LID: s.LID, Name: "baguette-tastes"}
}

func (s *BaguetteTaste) SetID(ID string) error {
s.ID = ID
func (s *BaguetteTaste) SetID(ID jsonapi.Identifier) error {
s.ID = ID.ID
s.LID = ID.LID
return nil
}

func (s BaguetteTaste) GetName() string {
return "baguette-tastes"
}

type BaguetteResource struct{}

func (s BaguetteResource) FindOne(ID string, req Request) (Responder, error) {
Expand Down Expand Up @@ -69,7 +68,7 @@ func (s BaguetteResource) Update(obj interface{}, req Request) (Responder, error
}, nil
}

var _ = Describe("Test route renaming with EntityNamer interface", func() {
var _ = Describe("Test route renaming with Identifier name", func() {
var (
api *API
rec *httptest.ResponseRecorder
Expand Down
6 changes: 3 additions & 3 deletions api_interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ type ObjectInitializer interface {
InitializeObject(interface{})
}

//URLResolver allows you to implement a static
//way to return a baseURL for all incoming
//requests for one api2go instance.
// URLResolver allows you to implement a static
// way to return a baseURL for all incoming
// requests for one api2go instance.
type URLResolver interface {
GetBaseURL() string
}
Expand Down
10 changes: 6 additions & 4 deletions api_interfaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@ import (

type SomeData struct {
ID string `json:"-"`
LID string `json:"-"`
Data string `json:"data"`
CustomerID string `json:"customerId"`
}

func (s SomeData) GetID() string {
return s.ID
func (s SomeData) GetID() jsonapi.Identifier {
return jsonapi.Identifier{ID: s.ID, LID: s.LID}
}

func (s *SomeData) SetID(ID string) error {
s.ID = ID
func (s *SomeData) SetID(ID jsonapi.Identifier) error {
s.ID = ID.ID
s.LID = ID.LID
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion api_public.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (api API) Handler() http.Handler {
return api.router.Handler()
}

//Router returns the specified router on an api instance
// Router returns the specified router on an api instance
func (api API) Router() routing.Routeable {
return api.router
}
Expand Down
59 changes: 32 additions & 27 deletions api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,27 @@ func (m *requestURLResolver) SetRequest(r http.Request) {

type invalid string

func (i invalid) GetID() string {
return "invalid"
func (i invalid) GetID() jsonapi.Identifier {
return jsonapi.Identifier{ID: "invalid", LID: "invalid"}
}

type Post struct {
ID string `json:"-"`
LID string `json:"-"`
Title string `json:"title"`
Value null.Float `json:"value"`
Author *User `json:"-"`
Comments []Comment `json:"-"`
Bananas []Banana `json:"-"`
}

func (p Post) GetID() string {
return p.ID
func (p Post) GetID() jsonapi.Identifier {
return jsonapi.Identifier{ID: p.ID, LID: p.LID}
}

func (p *Post) SetID(ID string) error {
p.ID = ID
func (p *Post) SetID(ID jsonapi.Identifier) error {
p.ID = ID.ID
p.LID = ID.LID
return nil
}

Expand All @@ -79,24 +81,24 @@ func (p Post) GetReferences() []jsonapi.Reference {
func (p Post) GetReferencedIDs() []jsonapi.ReferenceID {
result := []jsonapi.ReferenceID{}
if p.Author != nil {
result = append(result, jsonapi.ReferenceID{ID: p.Author.GetID(), Name: "author", Type: "users"})
result = append(result, jsonapi.ReferenceID{ID: p.Author.GetID().ID, Name: "author", Type: "users"})
}
for _, comment := range p.Comments {
result = append(result, jsonapi.ReferenceID{ID: comment.GetID(), Name: "comments", Type: "comments"})
result = append(result, jsonapi.ReferenceID{ID: comment.GetID().ID, Name: "comments", Type: "comments"})
}
for _, banana := range p.Bananas {
result = append(result, jsonapi.ReferenceID{ID: banana.GetID(), Name: "bananas", Type: "bananas"})
result = append(result, jsonapi.ReferenceID{ID: banana.GetID().ID, Name: "bananas", Type: "bananas"})
}

return result
}

func (p *Post) SetToOneReferenceID(name, ID string) error {
func (p *Post) SetToOneReferenceID(name string, ID *jsonapi.Identifier) error {
if name == "author" {
if ID == "" {
if ID == nil {
p.Author = nil
} else {
p.Author = &User{ID: ID}
p.Author = &User{ID: ID.ID, LID: ID.LID}
}

return nil
Expand All @@ -105,11 +107,11 @@ func (p *Post) SetToOneReferenceID(name, ID string) error {
return errors.New("There is no to-one relationship with the name " + name)
}

func (p *Post) SetToManyReferenceIDs(name string, IDs []string) error {
func (p *Post) SetToManyReferenceIDs(name string, IDs []jsonapi.Identifier) error {
if name == "comments" {
comments := []Comment{}
for _, ID := range IDs {
comments = append(comments, Comment{ID: ID})
comments = append(comments, Comment{ID: ID.ID, LID: ID.LID})
}
p.Comments = comments

Expand All @@ -119,7 +121,7 @@ func (p *Post) SetToManyReferenceIDs(name string, IDs []string) error {
if name == "bananas" {
bananas := []Banana{}
for _, ID := range IDs {
bananas = append(bananas, Banana{ID: ID})
bananas = append(bananas, Banana{ID: ID.ID, LID: ID.LID})
}
p.Bananas = bananas

Expand Down Expand Up @@ -150,7 +152,7 @@ func (p *Post) DeleteToManyIDs(name string, IDs []string) error {
for _, ID := range IDs {
// find and delete the comment with ID
for pos, comment := range p.Comments {
if comment.GetID() == ID {
if comment.GetID().ID == ID {
p.Comments = append(p.Comments[:pos], p.Comments[pos+1:]...)
}
}
Expand All @@ -161,7 +163,7 @@ func (p *Post) DeleteToManyIDs(name string, IDs []string) error {
for _, ID := range IDs {
// find and delete the comment with ID
for pos, banana := range p.Bananas {
if banana.GetID() == ID {
if banana.GetID().ID == ID {
p.Bananas = append(p.Bananas[:pos], p.Bananas[pos+1:]...)
}
}
Expand All @@ -187,30 +189,33 @@ func (p Post) GetReferencedStructs() []jsonapi.MarshalIdentifier {

type Comment struct {
ID string `json:"-"`
LID string `json:"-"`
Value string `json:"value"`
}

func (c Comment) GetID() string {
return c.ID
func (c Comment) GetID() jsonapi.Identifier {
return jsonapi.Identifier{ID: c.ID, LID: c.LID}
}

type Banana struct {
ID string `jnson:"-"`
LID string `jnson:"-"`
Name string
}

func (b Banana) GetID() string {
return b.ID
func (b Banana) GetID() jsonapi.Identifier {
return jsonapi.Identifier{ID: b.ID, LID: b.LID}
}

type User struct {
ID string `json:"-"`
LID string `json:"-"`
Name string `json:"name"`
Info string `json:"info"`
}

func (u User) GetID() string {
return u.ID
func (u User) GetID() jsonapi.Identifier {
return jsonapi.Identifier{ID: u.ID, LID: u.LID}
}

type fixtureSource struct {
Expand Down Expand Up @@ -934,7 +939,7 @@ var _ = Describe("RestHandler", func() {
}
}
`, "/v1/posts/1", "PATCH")
Expect(target.Author.GetID()).To(Equal("2"))
Expect(target.Author.GetID().ID).To(Equal("2"))
})

It("Patch can delete to-one relationships", func() {
Expand Down Expand Up @@ -975,7 +980,7 @@ var _ = Describe("RestHandler", func() {
}
}
`, "/v1/posts/1", "PATCH")
Expect(target.Comments[0].GetID()).To(Equal("2"))
Expect(target.Comments[0].GetID().ID).To(Equal("2"))
})

It("Patch can delete to-many relationships", func() {
Expand Down Expand Up @@ -1004,7 +1009,7 @@ var _ = Describe("RestHandler", func() {
}
}`, "/v1/posts/1/relationships/author", "PATCH")
target := source.posts["1"]
Expect(target.Author.GetID()).To(Equal("2"))
Expect(target.Author.GetID().ID).To(Equal("2"))
})

It("Relationship PATCH route updates to-many", func() {
Expand All @@ -1016,7 +1021,7 @@ var _ = Describe("RestHandler", func() {
}`, "/v1/posts/1/relationships/comments", "PATCH")
target := source.posts["1"]
Expect(target.Comments).To(HaveLen(1))
Expect(target.Comments[0].GetID()).To(Equal("2"))
Expect(target.Comments[0].GetID().ID).To(Equal("2"))
})

It("Relationship POST route adds to-many elements", func() {
Expand Down
Loading