Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
A

api2go

> 编程语言
Open source

JSONAPI.org Implementation for Go

721 stars0 likes1 views
WebsiteGitHub

About

JSONAPI.org Implementation for Go

api2go

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

TOC

  • Installation
  • Basic functionality
  • Examples
  • Interfaces to implement
    • Responder
    • EntityNamer
    • MarshalIdentifier
    • UnmarshalIdentifier
    • Marshalling with References to other structs
    • Unmarshalling with references to other structs
  • Manual marshalling / unmarshalling
  • SQL Null-Types
  • Using api2go with the gin framework
  • Building a REST API
    • Query Params
    • Using Pagination
    • Fetching related IDs
    • Fetching related resources
    • Using middleware
    • Dynamic URL Handling
  • Tests

Installation

For the complete api2go package use:

go
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:

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

Would json.Marshal into this Json:

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:

json
{
  "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

  • Basic Examples can be found here.
  • For a more real life example implementation of api2go using jinzhu/gorm and gin-gonic/gin you can have a look at hnakamur's repository

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.

go
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

go
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

go
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

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

MarshalIdentifier

go
type MarshalIdentifier interface {
	GetID() string
}

Implement this interface to marshal a struct.

UnmarshalIdentifier

go
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:

go
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.

go
// 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

go
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

…

You can also use jsonapi.MarshalWithURLs to automatically generate URLs for the rest endpoints that have a version and BaseURL prefix. This will generate the same routes that our API uses. This adds self and related fields for relations inside the relationships object.

Recover the structure from above using. Keep in mind that Unmarshalling with included structs does not work yet. So Api2go cannot be used as a client yet.

go
var posts []Post
err := jsonapi.Unmarshal(json, &posts)
// posts[0] == Post{ID: 1, Title: "Foobar", CommentsIDs: []int{1, 2}}

SQL Null-Types

When using a SQL Database it is most likely you want to use the special SQL-Types from the database/sql package. These are

  • sql.NullBool
  • sql.NullFloat64
  • sql.NullInt64
  • sql.NullString

The Problem is, that they internally manage the null value behavior by using a custom struct. In order to Marshal and Unmarshal these values, it is required to implement the json.Marshaller and json.Unmarshaller interfaces of the go standard library.

But you dont have to do this by yourself! There already is a library that did the work for you. We recommend that you use the types of this library: http://gopkg.in/guregu/null.v3/zero

In order to use omitempty with those types, you need to specify them as pointers in your struct.

Using api2go with the gin framework

If you want to use api2go with gin you need to use a different router than the default one. Get the according adapter using:

go get -tags=gingonic github.com/manyminds/api2go

Currently the supported tags are: gingonic,gorillamux, or echo.

After that you can bootstrap api2go the following way:

…

Keep in mind that you absolutely should map api2go under its own namespace to not get conflicts with your normal routes.

If you need api2go with any different go framework, just send a PR with the according adapter :-)

Building a REST API

First, write an implementation of either api2go.ResourceGetter, api2go.ResourceCreator, api2go.ResourceUpdater, api2go.ResourceDeleter, or any combination of them. You can also write an implementation the CRUD interface which embed all of them. You have to implement at least one of these 4 methods:

…

If you want to return a jsonapi compatible error because something went wrong inside the CRUD methods, you can use our HTTPError struct, which can be created with NewHTTPError. This allows you to set the error status code and add as many information about the error as you like. See: jsonapi error

To fetch all objects of a specific resource you can choose to implement one or both of the following interfaces:

go
type FindAll interface {
	// FindAll returns all objects
	FindAll(req Request) (Responder, error)
}

type PaginatedFindAll interface {
	PaginatedFindAll(req Request) (totalCount uint, response Responder, err error)
}

FindAll returns everything. You could limit the results only by using Query Params which are described here

PaginatedFindAll can also use Query Params, but in addition to that it does not need to send all

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Gogojsonapirest

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言