Skip to content
Merged
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
60 changes: 57 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ all of your data easily.

## Example App

[examples/app.go](https://github.com/google/jsonapi/blob/master/examples/app.go)
[examples/app.go](https://github.com/hashicorp/jsonapi/blob/main/examples/app.go)

This program demonstrates the implementation of a create, a show,
and a list [http.Handler](http://golang.org/pkg/net/http#Handler). It
Expand Down Expand Up @@ -179,6 +179,60 @@ used as the key in the `relationships` hash for the record. The optional
third argument is `omitempty` - if present will prevent non existent to-one and
to-many from being serialized.


#### `polyrelation`

```
`jsonapi:"polyrelation,<key name in relationships hash>,<optional: omitempty>"`
```

Polymorphic relations can be represented exactly as relations, except that
an intermediate type is needed within your model struct that provides a choice
for the actual value to be populated within.

Example:

```go
type Video struct {
ID int `jsonapi:"primary,videos"`
SourceURL string `jsonapi:"attr,source-url"`
CaptionsURL string `jsonapi:"attr,captions-url"`
}

type Image struct {
ID int `jsonapi:"primary,images"`
SourceURL string `jsonapi:"attr,src"`
AltText string `jsonapi:"attr,alt"`
}

type OneOfMedia struct {
Video *Video
Image *Image
}

type Post struct {
ID int `jsonapi:"primary,posts"`
Title string `jsonapi:"attr,title"`
Body string `jsonapi:"attr,body"`
Gallery []*OneOfMedia `jsonapi:"polyrelation,gallery"`
Hero *OneOfMedia `jsonapi:"polyrelation,hero"`
}
```

During decoding, the `polyrelation` annotation instructs jsonapi to assign each relationship
to either `Video` or `Image` within the value of the associated field, provided that the
payload contains either a "videos" or "images" type. This field value must be
a pointer to a special choice type struct (also known as a tagged union, or sum type) containing
other pointer fields to jsonapi models. The actual field assignment depends on that type having
a jsonapi "primary" annotation with a type matching the relationship type found in the response.
All other fields will be remain empty. If no matching types are represented by the choice type,
all fields will be empty.

During encoding, the very first non-nil field will be used to populate the payload. Others
will be ignored. Therefore, it's critical to set the value of only one field within the choice
struct. When accepting input values on this type of choice type, it would a good idea to enforce
and check that the value is set on only one field.

#### `links`

*Note: This annotation is an added feature independent of the canonical google/jsonapi package*
Expand Down Expand Up @@ -471,13 +525,13 @@ I use git subtrees to manage dependencies rather than `go get` so that
the src is committed to my repo.

```
git subtree add --squash --prefix=src/github.com/google/jsonapi https://github.com/google/jsonapi.git master
git subtree add --squash --prefix=src/github.com/hashicorp/jsonapi https://github.com/hashicorp/jsonapi.git main
```

To update,

```
git subtree pull --squash --prefix=src/github.com/google/jsonapi https://github.com/google/jsonapi.git master
git subtree pull --squash --prefix=src/github.com/hashicorp/jsonapi https://github.com/hashicorp/jsonapi.git main
```

This assumes that I have my repo structured with a `src` dir containing
Expand Down
21 changes: 11 additions & 10 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ package jsonapi

const (
// StructTag annotation strings
annotationJSONAPI = "jsonapi"
annotationPrimary = "primary"
annotationClientID = "client-id"
annotationAttribute = "attr"
annotationRelation = "relation"
annotationLinks = "links"
annotationOmitEmpty = "omitempty"
annotationISO8601 = "iso8601"
annotationRFC3339 = "rfc3339"
annotationSeperator = ","
annotationJSONAPI = "jsonapi"
annotationPrimary = "primary"
annotationClientID = "client-id"
annotationAttribute = "attr"
annotationRelation = "relation"
annotationPolyRelation = "polyrelation"
annotationLinks = "links"
annotationOmitEmpty = "omitempty"
annotationISO8601 = "iso8601"
annotationRFC3339 = "rfc3339"
annotationSeparator = ","

iso8601TimeFormat = "2006-01-02T15:04:05Z"

Expand Down
2 changes: 1 addition & 1 deletion examples/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"net/http/httptest"
"time"

"github.com/google/jsonapi"
"github.com/hashicorp/jsonapi"
)

func main() {
Expand Down
2 changes: 1 addition & 1 deletion examples/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"net/http"
"strconv"

"github.com/google/jsonapi"
"github.com/hashicorp/jsonapi"
)

const (
Expand Down
2 changes: 1 addition & 1 deletion examples/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"net/http/httptest"
"testing"

"github.com/google/jsonapi"
"github.com/hashicorp/jsonapi"
)

func TestExampleHandler_post(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion examples/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"
"time"

"github.com/google/jsonapi"
"github.com/hashicorp/jsonapi"
)

// Blog is a model representing a blog site
Expand Down
24 changes: 24 additions & 0 deletions models_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,27 @@ type CustomAttributeTypes struct {
Float CustomFloatType `jsonapi:"attr,float"`
String CustomStringType `jsonapi:"attr,string"`
}

type Image struct {
ID string `jsonapi:"primary,images"`
Src string `jsonapi:"attr,src"`
}

type Video struct {
ID string `jsonapi:"primary,videos"`
Captions string `jsonapi:"attr,captions"`
}

type OneOfMedia struct {
Image *Image
random int
Video *Video
RandomStuff *string
}

type BlogPostWithPoly struct {
ID string `jsonapi:"primary,blogs"`
Title string `jsonapi:"attr,title"`
Hero *OneOfMedia `jsonapi:"polyrelation,hero-media,omitempty"`
Media []*OneOfMedia `jsonapi:"polyrelation,media,omitempty"`
}
Loading