SkillAgentSearch skills...

Api2go

JSONAPI.org Implementation for Go

Install / Use

/learn @manyminds/Api2go
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

api2go

Join the chat at https://gitter.im/manyminds/api2go GoDoc Build Status Coverage Status Go Report Card

A JSON API Implementation for Go, to be used e.g. as server for Ember Data.

TOC

Installation

For the complete api2go package use:

go get github.com/manyminds/api2go

If you only need marshalling and/or unmarshalling:

go get github.com/manyminds/api2go/jsonapi 

Basic functionality

Api2go will Marshal/Unmarshal exactly like the internal json package from Go with one addition: It will decorate the Marshalled json with jsonapi meta objects. Jsonapi wraps the payload inside an attributes object. The rest is just Meta-Data which will be generated by api2go.

So let's take this basic example:

type Article struct {
	ID    string
	Title string `json:"title"`
}

Would json.Marshal into this Json:

{
  "ID": "Some-ID",
  "title": "the title"
}

For api2go, you have to ignore tag the ID field and then the result could be something like this:

{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "Rails is Omakase"
  },
  "relationships": {
    "author": {
      "links": {
        "self": "/articles/1/relationships/author",
        "related": "/articles/1/author"
      },
      "data": { "type": "people", "id": "9" }
    }
  }
}

All the additional information is retrieved by implementing some interfaces.

Examples

Interfaces to implement

For the following query and result examples, imagine the following 2 structs which represent a posts and comments that belong with a has-many relation to the post.

type Post struct {
  ID          int       `json:"-"`  // Ignore ID field because the ID is fetched via the
                                    // GetID() method and must not be inside the attributes object.
  Title       string    `json:"title"`
  Comments    []Comment `json:"-"` // this will be ignored by the api2go marshaller
  CommentsIDs []int     `json:"-"` // it's only useful for our internal relationship handling
}

type Comment struct {
  ID   int    `json:"-"`
  Text string `json:"text"`
}

You must at least implement the MarshalIdentifier interface, which is the one for marshalling/unmarshalling the primary ID of the struct that you want to marshal/unmarshal. This is because of the huge variety of types that you could use for the primary ID. For example a string, a UUID or a BSON Object for MongoDB etc...

In the Post example struct, the ID field is ignored because api2go will use the GetID method that you implemented for your struct to fetch the ID of the struct. Every field inside a struct will be marshalled into the attributes object in the json. In our example, we just want to have the Title field there.

Don't forget to name all your fields with the json:"yourName" tag.

Responder

type Responder interface {
	Metadata() map[string]interface{}
	Result() interface{}
	StatusCode() int
}

The Responder interface must be implemented if you are using our API. It contains everything that is needed for a response. You can see an example usage of it in our example project.

EntityNamer

type EntityNamer interface {
	GetName() string
}

EntityNamer is an optional interface. Normally, the name of a struct will be automatically generated in its plural form. For example if your struct has the type Post, its generated name is posts. And the url for the GET request for post with ID 1 would be /posts/1.

If you implement the GetName() method and it returns special-posts, then this would be the name in the type field of the generated json and also the name for the generated routes.

Currently, you must implement this interface, if you have a struct type that consists of multiple words and you want to use a hyphenized name. For example UnicornPost. Our default Jsonifier would then generate the name unicornPosts. But if you want the recommended name, you have to implement GetName

func (s UnicornPost) GetName() string {
	return "unicorn-posts"
}

MarshalIdentifier

type MarshalIdentifier interface {
	GetID() string
}

Implement this interface to marshal a struct.

UnmarshalIdentifier

type UnmarshalIdentifier interface {
	SetID(string) error
}

This is the corresponding interface to MarshalIdentifier. Implement this interface in order to unmarshal incoming json into a struct.

Marshalling with References to other structs

For relationships to work, there are 3 Interfaces that you can use:

type MarshalReferences interface {
	GetReferences() []Reference
}

// MarshalLinkedRelations must be implemented if there are references and the reference IDs should be included
type MarshalLinkedRelations interface {
	MarshalReferences
	MarshalIdentifier
	GetReferencedIDs() []ReferenceID
}

// MarshalIncludedRelations must be implemented if referenced structs should be included
type MarshalIncludedRelations interface {
	MarshalReferences
	MarshalIdentifier
	GetReferencedStructs() []MarshalIdentifier
}

Implementing those interfaces is not mandatory and depends on your use cases. If your API has any relationships, you must at least implement MarshalReferences and MarshalLinkedRelations.

MarshalReferences must be implemented in order for api2go to know which relations are possible for your struct.

MarshalLinkedRelations must be implemented to retrieve the IDs of the relations that are connected to this struct. This method could also return an empty array, if there are currently no relations. This is why there is the MarshalReferences interface, so that api2go knows what is possible, even if nothing is referenced at the time.

In addition to that, you can implement MarshalIncludedRelations which exports the complete referenced structs and embeds them in the json result inside the included object.

That way you can choose how you internally manage relations. So, there are no limits regarding the use of ORMs.

Unmarshalling with references to other structs

Incoming jsons can also contain reference IDs. In order to unmarshal them correctly, you have to implement the following interfaces. If you only have to-one relationships, the UnmarshalToOneRelations interface is enough.

// UnmarshalToOneRelations must be implemented to unmarshal to-one relations
type UnmarshalToOneRelations interface {
	SetToOneReferenceID(name, ID string) error
}

// UnmarshalToManyRelations must be implemented to unmarshal to-many relations
type UnmarshalToManyRelations interface {
	SetToManyReferenceIDs(name string, IDs []string) error
}

If you need to know more about how to use the interfaces, look at our tests or at the example project.

Manual marshalling / unmarshalling

Please keep in mind that this only works if you implemented the previously mentioned interfaces. Manual marshalling and unmarshalling makes sense, if you do not want to use our API that automatically generates all the necessary routes for you. You can directly use our sub-package github.com/manyminds/api2go/jsonapi

comment1 = Comment{ID: 1, Text: "First!"}
comment2 = Comment{ID: 2, Text: "Second!"}
post = Post{ID: 1, Title: "Foobar", Comments: []Comment{comment1, comment2}}

json, err := jsonapi.Marshal(post)

will yield

{
  "data": [
    {
      "id": "1",
      "type": "posts",
      "attributes": {
        "title": "Foobar"
      },
      "relationships": {
        "comments": {
          "data": [
            {
              "id": "1",
              "type": "comments"
            },
            {
              "id": "2",
              "type": "comments"
            }
          ]
        }
      }
    }
  ],
  "included": [
    {
      "id": "1",
      "type": "comments",
      "attributes"

Related Skills

View on GitHub
GitHub Stars720
CategoryDevelopment
Updated14d ago
Forks96

Languages

Go

Security Score

100/100

Audited on Mar 12, 2026

No findings