Categorygithub.com/gonobo/jsonapi/v2
modulepackage
2.2.0
Repository: https://github.com/gonobo/jsonapi.git
Documentation: pkg.go.dev

# README

jsonapi

Test GoDoc Release

Yet Another JSON API library for Go.

Package jsonapi provides structures and functions to implement JSON API compatible APIs. The library can be used with any framework and is built on top of the standard Go http library.

Installation

Get the package using the go tool:

$ go get -u github.com/gonobo/jsonapi/v2

Structures

This library uses StructField tags to annotate the structs fields that you already have and use in your app and then reads and writes JSON API output based on the tag content.

type Customer struct {
  ID   string `jsonapi:"primary,customers"`
  Name string `jsonapi:"attr,name"`
}

type Order struct {
  ID       string     `jsonapi:"primary,orders"`
  Customer *Customer  `jsonapi:"relation,customer"`
  Products []*Product `jsonapi:"relation,products,omitempty"`
}

type Product struct {
  ID string   `jsonapi:"primary,products"`
  Name string `jsonapi:"attr,name"`
}

// This object...
order := Order{
  ID:       "1",
  Customer: &Customer{ID: "2", Name: "John"},
  Products: []*Product{
    {ID: "42", Name: "Shoes"},
    {ID: "24", Name: "Socks"},
  }
}

// ...is transformed into this resource when marshaled.
resource := jsonapi.Resource{
  ID:   "1",
  Type: "orders",
  Relationships: jsonapi.Relationships{
    "customer": &jsonapi.Relationship{
      Data: jsonapi.One{
        Value: &jsonapi.Resource{
          ID:         "2",
          Type:       "customers",
          Attributes: map[string]any{"name": "John"},
        }}
    },
    "products": &jsonapi.Relationship{
      Data: jsonapi.Many{
        Values: []*jsonapi.Resource{
          {
            ID:         "42",
            Type:       "products",
            Attributes: map[string]any{"name": "Shoes"}
          },
          {
            ID:         "24",
            Type:       "products",
            Attributes: map[string]any{"name": "Socks"}
          },
        },
      },
    },
  }
}

Permitted Tag Values

Struct tag values are equivalent to those found in the Google JSON API library:

primary

`jsonapi:"primary,<type field output>"`

This indicates this is the primary key field for this struct type. Tag value arguments are comma separated. The first argument must be, primary, and the second must be the name that should appear in the type* field for all data objects that represent this type of model.

* According the JSON API spec, the plural record types are shown in the examples, but not required.

attr

`jsonapi:"attr,<key name in attributes hash>,<optional: omitempty>"`

These fields' values will end up in the attributeshash for a record. The first argument must be, attr, and the second should be the name for the key to display in the attributes hash for that record. The optional third argument is omitempty - if it is present the field will not be present in the "attributes" if the field's value is equivalent to the field types empty value (ie if the count field is of type int, omitempty will omit the field when count has a value of 0). Lastly, the spec indicates that attributes key names should be dasherized for multiple word field names.

relation

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

Relations are struct fields that represent a one-to-one or one-to-many relationship with other structs. JSON API will traverse the graph of relationships and marshal or unmarshal records. The first argument must be, relation, and the second should be the name of the relationship, 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.

Marshaling and Unmarshaling

All Marshal and Unmarshal methods expect pointers to struct instance or slices of the same type. Using values during marshaling and unmarshal is undefined behavior.

import "github.com/gonobo/jsonapi/v2"

func createOrder(w *http.ResponseWriter, r *http.Request) {
  in, err := jsonapi.Decode(r.Body)
  order := Order{}
  err = jsonapi.Unmarshal(in, &order)

  newOrder, err := db.CreateNewOrder(order)
  out, err := jsonapi.Marshal(newOrder)
  w.WriteHeader(http.StatusCreated)
  err = jsonapi.Write(w, out)
}

JSON:API Server

The server package contains structs and methods for handling http requests that conform to the JSON:API specification.

The server.Handler struct wraps a standard http.Handler instance, inferring the JSON:API context from the request:

import (
  "net/http"

  "github.com/gonobo/jsonapi/v2"
  "github.com/gonobo/jsonapi/v2/server"
)

func main() {
  mux := http.NewServeMux()
  mux.Handle(
    "GET /orders/42/relationships/customer",
    http.HandleFunc(getOrderCustomer),
  )

  handler := jsonapi.Handle(mux)
  http.ListenAndServe(":3000", handler)
}

func getOrderCustomer(w http.ResponseWriter, r *http.Request) {
  ctx := jsonapi.Context(r.Context())

  log.Printf("type: %s", ctx.ResourceType)         // "orders"
  log.Printf("id: %s", ctx.ResourceID)             // "42"
  log.Printf("relationship: %s", ctx.Relationship) // "customer"
  
  order, err := db.GetOrder(ctx, ctx.ResourceID)
  if err != nil {
    // return an JSON:API error document with the error message
    // reflected in the details field.
    server.Error(w, err, http.StatusInternalServerError)
    return
  }

  // write the order's customer as a resource reference in the
  // response document.
  server.Write(w, order, http.StatusOk,
    server.WriteRef("customer"),
  )
}

There are additional handlers that can take care of routing requests to their proper handler:

import (
  "net/http"

  "github.com/gonobo/jsonapi/v2"
  "github.com/gonobo/jsonapi/v2/server"
)

func main() {
  mux := http.NewServeMux()
  mux.Handle("/",
    server.ResourceMux{
      "orders": server.Resource{
        Get:             http.HandlerFunc(getOrder),      // GET /orders/42
        Create:          http.HandlerFunc(createOrder),   // POST /orders
        List:            http.HandlerFunc(searchOrders),  // GET /orders
        Relationships:   server.RelationshipMux{
          "customer": server.Relationship{
            Get: http.HandlerFunc(getOrderCustomer),      // GET /orders/42/relationships/customer
          },
        },
      },
    },
  )

  handler := jsonapi.Handle(mux)
  http.ListenAndServe(":3000", handler)
}

The handlers only deal with http.Handler instances so you can control the degree of precision.

Examples

TBD.

License

The MIT License (MIT)

Copyright (c) 2024 Nathan Simpson

# Packages

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Functions

ContextResolverWithPrefix returns a resolver that populates a JSON:API context based on the URL path examples given by the JSON:API specification: "/prefix/:type" // ResourceType "/prefix/:type/:id" // ResourceType, ResourceID "/prefix/:type/:id/relationships/:ref" // ResourceType, ResourceID, Relationship "/prefix/:type/:id/:ref" // ResourceType, ResourceID, Relationship, Related The specified prefix should start -- but not end -- with a forward slash.
Decode reads the JSON-encoded document from its input and stores it in the input document.
DefaultContextResolver returns a resolver that populates a JSON:API context based on the URL path examples given by the JSON:API specification: "/:type" // ResourceType "/:type/:id" // ResourceType, ResourceID "/:type/:id/relationships/:ref" // ResourceType, ResourceID, Relationship "/:type/:id/:ref" // ResourceType, ResourceID, Relationship, Related.
DefaultURLResolver returns a resolver that generates the following urls based on the request context (given a base url): ":base/:type" for search, create ":base/:type/:id" for fetch, update, delete ":base/:type/:id/relationships/:ref" for fetchRef ":base/:type/:id/:ref" for fetchRelated.
Do sends a request to the server.
Encode writes the JSON encoding of v to the stream, followed by a newline character.
FromContext returns the JSON:API FromContext from the parent context.
Marshal generates a JSON:API document from the specified value.
MarshalRaw serializes the input value to its JSON equivalent, wrapped in a RawMessage type for ease of use.
MarshalRef generates a JSON:API document, using a resource's relationship as primary data.
MarshalResource generates a JSON:API resource object based on the input struct's fields.
NewError creates a new ErrorNode with the given status and title.
NewMultiDocument creates a new document with the provided resources as primary data.
NewRequest creates a new JSON:API request instance.
NewSingleDocument creates a new document with the provided resource as primary data.
RequestWithContext sets the request context on the provided request.
ResourceComparator returns a Comparator that compares two resources a and b based on an attribute specified by the key index of map m.
Unmarshal populates the output struct or slice with information stored inside the provided document.
UnmarshalResource populates the output struct's fields with information stored inside the provided resource node.
WithContext sets the JSON:API Context in the parent context.

# Constants

No description provided by the author
No description provided by the author

# Variables

No description provided by the author

# Structs

Client is a JSON:API http client.
DefaultJSONEncoder is a wrapper that implements JSONEncoder by calling: json.NewEncoder(w).Encode(value).
Document is the highest order node, containing either a single resource or collection of resources in response to a client request.
Error provides additional information about problems encountered while performing an operation.
ErrorSource is an object containing references to the primary source of the error.
JSONAPI includes information about the server's implementation.
Link represents a single link.
Many is a data node that represents a "to-many" relationship or a document's primary data.
One is a data node that represents either a "to-one" relationship or a document's primary data.
Relationship describes a resource's relationships.
RequestContext contains information about the JSON:API request that defines it.
Resource represents a server resource.

# Interfaces

Comparator compares two resources and determines ordinality by comparing the values of a specified attribute.
ContextResolver resolves JSON:API context information from an incoming http request.
No description provided by the author
Doer is responsible for sending HTTP requests.
JSONEncoder is responsible for encoding JSON data.
LinksMarshaler creates links associated with the instance when marshaled.
LinksUnmarshaler can extract links from a resource node and populate itself.
MetaMarshaler creates metadata associated with the instance when marshaled.
MetaUnmarshaler can extract metadata from a resource node and populate itself.
PrimaryData interfaces provide document primary data or resource relationship data.
RelatedLinksMarshaler creates links associated with an instance's relationships when marshaled.
RelatedLinksUnmarshaler can extract relationship links from a node and populate itself.
RelatedMetaMarshaler creates metadata associated with an instance's relationships when marshaled.
RelatedMetaUnmarshaler can extract relationship metadata from a node and populate itself.
ResourceMarshaler can marshal its information into a resource node.
ResourceUnmarshaler can extract information from a resource node and populate itself.
URLResolver resolves urls based on the JSON:API request context.

# Type aliases

ComparatorFunc functions implement Comparator.
Comparer determines the order of two items.
ContextResolverFunc functions implement ContextResolver.
ExtensionsNode contains data defined by JSON:API extensions.
HrefLang is a string or an array of strings indicating the language(s) of the link’s target.
Links contains the links defined within a resource, document, or error.
Meta contains non-standard information within a document.
RelationshipsNode contains the relationships defined within a resource.
URLResolverFunc functions implement URLResolver.
Version contains information regarding the JSON:API version supported by the server.