gomo

package module
v0.0.0-...-d5453b7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 1, 2019 License: MIT Imports: 15 Imported by: 0

README

gomo - a Go Client for the Moltin API

GoDoc Report Card Maintainability Test Coverage

A Golang client for the moltin API.

go get github.com/moltin/gomo

Documentation

Reference documentation is available on GoDoc.

client := gomo.NewClient(
	gomo.ClientCredentials(
		os.Getenv("MOLTIN_CLIENT_ID"),
		os.Getenv("MOLTIN_CLIENT_SECRET"),
	),
)

if err := client.Authenticate(); err != nil {
	log.Fatal(err)
}

products := []entities.Product{}
err := client.Get("products", gomo.Data(&products))
if err != nil {
	log.Fatal(err)
}

log.Printf("Found %d products\n", len(products))

Testing

In order to fully test the package, you will need a Moltin account to add your credentials to an environment file:

cp .env.example .env

Add your credentials and run:

source .env && go test ./...

If you do not supply a MOLTIN_CLIENT_ID and MOLTIN_CLIENT_SECRET, we will skip tests that leverage the live API.

Documentation

Overview

Package gomo provides an API client for Moltin's headless ecommerce API.

Sign up for an account at https://moltin.com.

By Andrew Waters and the team at Moltin. Contributions are most welcome.

Getting Started

Create a client object, and authenticate:

client := gomo.NewClient()
err := client.Authenticate()

By default the environment variables MOLTIN_CLIENT_ID and MOLTIN_CLIENT_SECRET will be used for authentication.

Requests are made to the API via the Get(), Post(), Put() and Delete() functions, each of which accepts a path and a number of resources. These resources can set the target for the returned data or the body of the request, as will as configuring various other request options.

Requests and their responses are usually marshalled into core types representing the various objects in the Moltin API.

So to read category ID c82d2f00-bc66-4c7d-984a-8765222abb98, along with its associated products one might use:

id := "c82d2f00-bc66-4c7d-984a-8765222abb98"
var category core.Category
var included struct {
	Products []core.Product `json:"products"`
}
err := client.Get(
	"categories/"+id,
	gomo.Include("products"),
	gomo.Included(&included),
	gomo.Data(&category)
)
if err != nil {
	log.Fatal(err)
}
fmt.Printf("Category %s has products:\n", category.Name)
for _, product := range included.Products {
	fmt.Println(product.ID)
}

Flows

Flows allow arbitrary data to be associated with objects. To cope with them in Go, create a struct for the flow fields and embed the core object to access the core fields, eg:

type MyProduct struct {
	core.Product
	Stars int `json:"stars"`
}
var product MyProduct
err = client.Get(
	"/products/8610c22b-f3a5-48a6-a680-8e8902a74aac",
	gomo.Data(&product),
)
if err != nil {
	log.Fatal(err)
}
fmt.Printf(
	"Product %s has %d stars\n",
	product.Product.Name,
	product.Stars,
)
Example
package main

import (
	"fmt"
	"log"

	"github.com/moltin/gomo"
	"github.com/moltin/gomo/core"
)

func main() {
	// create a new client with client credentials
	client := gomo.NewClient(
		gomo.ClientCredentials(
			"client_id",
			"client_secret",
		),
	)
	// handle an authentication error
	if err := client.Authenticate(); err != nil {
		log.Fatal(err)
	}

	// create a product
	product := core.Product{
		Name: "My new product",
	}

	var executionTime *gomo.APIExecution
	// send the create request
	err := client.Post(
		"products",
		gomo.Body(product),
		gomo.Data(&product),
		gomo.ExecutionTime(&executionTime),
	)
	if err != nil {
		log.Fatal(err)
	}

	// print the execution time metric
	log.Println("Execution time:", executionTime.Elapsed())

	// update a product field
	product.Name = "Updated Product"

	// send the update request
	err = client.Put(
		fmt.Sprintf("products/%s", product.ID),
		gomo.Body(product),
	)
	if err != nil {
		log.Fatal(err)
	}

	// delete the product
	err = client.Delete(fmt.Sprintf("products/%s", product.ID))
	if err != nil {
		log.Fatal(err)
	}
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Iterate

func Iterate(limit int, f func(RequestResource) error) error

Iterate calls the function with a RequestResource that should be passed to a Get() request. The function is called for each page of size limit. If the function returns an error at any point the iteration stops and the error is returned.

Example
package main

import (
	"log"

	"github.com/moltin/gomo"
	"github.com/moltin/gomo/core"
)

func main() {
	client := gomo.NewClient()
	_ = client.Authenticate()

	gomo.Iterate(
		100,
		func(paginate gomo.RequestResource) error {
			page := []core.Product{}
			err := client.Get("product", gomo.Data(&page))
			if err != nil {
				log.Fatal(err)
			}
			log.Printf("%d products in page\n", len(page))
			return nil
		},
	)
}
Output:

func MorePages

func MorePages(meta core.Meta) bool

MorePages returns true is the meta suggests there are more results available

Example
package main

import (
	"fmt"
	"log"

	"github.com/moltin/gomo"
	"github.com/moltin/gomo/core"
)

func main() {
	client := gomo.NewClient()
	_ = client.Authenticate()

	var orders []core.Order
	var meta core.Meta
	err := client.Get("orders", gomo.Data(&orders), gomo.Meta(&meta))
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Got %d orders.\n", len(orders))
	if gomo.MorePages(meta) {
		fmt.Println("There are more orders to fetch!")
	}
}
Output:

func NextPage

func NextPage(meta core.Meta) (int, int)

NextPage advances the supplied Meta to the next page by returning a new offset and limit

Example
package main

import (
	"fmt"
	"log"

	"github.com/moltin/gomo"
	"github.com/moltin/gomo/core"
)

func main() {
	client := gomo.NewClient()
	_ = client.Authenticate()

	// Note that Iterate() is a neater way of doing this.
	var allOrders []core.Order
	offset := 0
	limit := 100
	for {
		var page []core.Order
		var meta core.Meta
		err := client.Get(
			"orders",
			gomo.Data(&page),
			gomo.Meta(&meta),
			gomo.Paginate(offset, limit),
		)
		if err != nil {
			log.Fatal(err)
		}
		allOrders = append(allOrders, page...)
		if !gomo.MorePages(meta) {
			break
		}
		offset, limit = gomo.NextPage(meta)
	}
	fmt.Printf("Got all the orders, a total of %d\n", len(allOrders))
}
Output:

Types

type APIError

type APIError struct {
	Status int    `json:"status"`
	Detail string `json:"detail"`
	Title  string `json:"title"`
}

APIError is an error returned by the API so that you can include error speciifc logic in your own implementation

if error.Status == 404 {
	// create something
}

func (APIError) String

func (e APIError) String() string

type APIExecution

type APIExecution struct {
	StartTime time.Time
	EndTime   time.Time
	// contains filtered or unexported fields
}

APIExecution records the execution time of the call

func (APIExecution) Elapsed

func (e APIExecution) Elapsed() time.Duration

Elapsed returns the duration of the timer

func (*APIExecution) End

func (e *APIExecution) End()

End the timer

func (*APIExecution) Start

func (e *APIExecution) Start()

Start the timer

type Client

type Client struct {
	APIVersion  string
	Endpoint    string
	AccessToken string
	Debug       bool
	Logs        []interface{}

	Logger func(*Client, interface{})
	// contains filtered or unexported fields
}

Client is the main client struct

func NewClient

func NewClient(options ...ClientOption) Client

NewClient creates a new client for you to make requests with. It is configured by passing in list of option functions.

Example
package main

import (
	"log"

	"github.com/moltin/gomo"
)

func main() {
	client := gomo.NewClient(
		gomo.ClientCredentials(
			"client_id",
			"client_secret",
		),
		gomo.Endpoint("http://test.example.com/"),
		gomo.Debug(),
	)
	log.Println(client.APIVersion)
}
Output:

func (*Client) Authenticate

func (c *Client) Authenticate() error

Authenticate makes a call to get the access token for the client's credentials

func (*Client) Delete

func (c *Client) Delete(endpoint string, resource ...RequestResource) error

Delete makes a DELETE request to the API

func (*Client) DisableDebug

func (c *Client) DisableDebug()

DisableDebug stops logs form API calls

func (*Client) EnableDebug

func (c *Client) EnableDebug()

EnableDebug logs debugging info from the API calls

func (*Client) Get

func (c *Client) Get(endpoint string, resource ...RequestResource) error

Get makes a GET request to the API

Example
package main

import (
	"fmt"
	"log"

	"github.com/moltin/gomo"
	"github.com/moltin/gomo/core"
)

func main() {
	client := gomo.NewClient()
	_ = client.Authenticate()

	id := "96a52ef6-62c0-47ad-809d-6390d7727d49"
	type MyProduct struct {
		core.Product
		FlowField string `json:"flow_field"`
	}
	var product MyProduct
	err := client.Get(
		fmt.Sprintf("products/%s", id),
		gomo.Data(&product),
	)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf(
		"Product %s has flow field %s\n",
		product.Product.ID,
		product.FlowField,
	)
}
Output:

func (*Client) GrantType

func (c *Client) GrantType() string

GrantType returns the string value of the current crednetials grant type

func (*Client) Log

func (c *Client) Log(msgs ...interface{})

Log will dump debug info onto stdout

func (*Client) Post

func (c *Client) Post(endpoint string, resource ...RequestResource) error

Post makes a POST request to the API

Example
package main

import (
	"fmt"
	"log"

	"github.com/moltin/gomo"
	"github.com/moltin/gomo/core"
)

func main() {
	client := gomo.NewClient()
	_ = client.Authenticate()

	type MyProduct struct {
		core.Product
		FlowField string `json:"flow_field"`
	}
	product := MyProduct{
		Product: core.Product{
			Name: "foo",
		},
		FlowField: "foo custom",
	}
	err := client.Post(
		"products",
		gomo.Body(product),
		gomo.Data(&product),
	)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Created product %s\n", product.Product.ID)
}
Output:

func (*Client) Put

func (c *Client) Put(endpoint string, resource ...RequestResource) error

Put makes a PUT request to the API

type ClientOption

type ClientOption func(*Client)

ClientOption are functions that configure a Client

func APIVersion

func APIVersion(apiVersion string) ClientOption

APIVersion configures the API version for the client

func ClientCredentials

func ClientCredentials(clientID string, clientSecret string) ClientOption

ClientCredentials configures a client with client credentials

Example
package main

import (
	"github.com/moltin/gomo"
)

func main() {
	creds := gomo.ClientCredentials(
		"client_id",
		"client_secret",
	)
	gomo.NewClient(creds)
}
Output:

func Debug

func Debug() ClientOption

Debug turns on client debugging, which is off by default

func Endpoint

func Endpoint(endpoint string) ClientOption

Endpoint configures the API endpoint for the client

func HTTPClient

func HTTPClient(client *http.Client) ClientOption

HTTPClient configures a client to use an http.Client

func ImplicitCredentials

func ImplicitCredentials(clientID string) ClientOption

ImplicitCredentials configures a client with implicit credentials

Example
package main

import (
	"github.com/moltin/gomo"
)

func main() {
	creds := gomo.ImplicitCredentials(
		"client_id",
	)
	gomo.NewClient(creds)
}
Output:

func Logger

func Logger(logger func(*Client, interface{})) ClientOption

Logger configures a client to use a logger

type RequestResource

type RequestResource func(*wrapper)

RequestResource are functions that provide a request with the resources it requires. This includes Body() which is the body of the request, Data() which sets the target struct for the returned data, etc

func Body

func Body(target interface{}) RequestResource

Body sets the body for a Post() or Put() request

func Data

func Data(target interface{}) RequestResource

Data sets a target for a responses data resource

func Errors

func Errors(target *[]APIError) RequestResource

Errors sets a target for the responses errors

func ExecutionTime

func ExecutionTime(e **APIExecution) RequestResource

ExecutionTime returns a pointer to the ExecutionTime for the request

func Filter

func Filter(filter string) RequestResource

Filter adds a filter to a query, prepending to any existing filters. See https://docs.moltin.com/api/basics/filtering

Example
package main

import (
	"fmt"
	"log"

	"github.com/moltin/gomo"
	"github.com/moltin/gomo/core"
)

func main() {
	client := gomo.NewClient()
	_ = client.Authenticate()

	var draftProducts []core.Product
	err := client.Get(
		"products",
		gomo.Filter("eq(status,draft)"),
		gomo.Data(&draftProducts),
	)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Draft products:")
	for _, product := range draftProducts {
		fmt.Println(product.ID)
	}
}
Output:

func Form

func Form(target interface{}) RequestResource

Form sets multipart/form data for a Post() or Put() request

Example
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/moltin/gomo"
	"github.com/moltin/gomo/core"
	"github.com/moltin/gomo/form"
)

func main() {
	client := gomo.NewClient()
	_ = client.Authenticate()

	img, err := os.Open("/tmp/product.jpg")
	if err != nil {
		log.Fatal(err)
	}

	file := core.File{
		FileName: "product.jpg",
		Public:   true,
		MimeType: "image/jpeg",
		File: &form.File{
			Name:    "product.jpg",
			Content: img,
		},
	}
	err = client.Post(
		"files",
		gomo.Form(file),
		gomo.Data(&file),
	)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("File ID: %s\n", file.ID)
}
Output:

func Include

func Include(include string) RequestResource

Include adds a resource to be included in the request. See https://docs.moltin.com/api/basics/includes

Example
package main

import (
	"fmt"
	"log"

	"github.com/moltin/gomo"
	"github.com/moltin/gomo/core"
)

func main() {
	client := gomo.NewClient()
	_ = client.Authenticate()

	id := "c82d2f00-bc66-4c7d-984a-8765222abb98"
	var included struct {
		Products []core.Product `json:"products"`
	}
	err := client.Get(
		"categories/"+id,
		gomo.Include("products"),
		gomo.Included(&included),
	)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Category %s has products:\n", id)
	for _, product := range included.Products {
		fmt.Println(product.ID)
	}
}
Output:

func Included

func Included(target interface{}) RequestResource

Included sets a target for a responses included resource

func Links(target interface{}) RequestResource

Links sets a target for a responses links resource

func Meta

func Meta(target interface{}) RequestResource

Meta sets the a for a responses meta resource

func Paginate

func Paginate(offset, limit int) RequestResource

Paginate sets the page to select bases on the offset and limit. See https://docs.moltin.com/api/basics/pagination

func Sort

func Sort(by string) RequestResource

Sort sorts the results. See https://docs.moltin.com/api/basics/sorting

Example
package main

import (
	"fmt"
	"log"

	"github.com/moltin/gomo"
	"github.com/moltin/gomo/core"
)

func main() {
	client := gomo.NewClient()
	_ = client.Authenticate()

	var productsByName []core.Product
	err := client.Get(
		"products",
		gomo.Sort("name"),
		gomo.Data(&productsByName),
	)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Product names:")
	for _, product := range productsByName {
		fmt.Println(product.Name)
	}
}
Output:

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL