shelfatlas

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2026 License: MIT Imports: 10 Imported by: 0

README

shelfatlas-go

Official, typed Go client for the ShelfAtlas Catalog API — read access to normalised Danish retail catalog data (products, offers, stores, chains, and price history). Standard library only, zero third-party dependencies.

Install

go get github.com/SlambertDK/shelfatlas-go

Requires Go 1.23+ (uses range-over-func iterators).

Authentication

Every request is authenticated with a ShelfAtlas API key (Authorization: Bearer sa_live_<key>). Create one in your ShelfAtlas dashboard and keep it server-side.

Quick start

package main

import (
	"context"
	"fmt"
	"log"

	shelfatlas "github.com/SlambertDK/shelfatlas-go"
)

func main() {
	client := shelfatlas.NewClient("https://api.shelfatlas.com", "sa_live_…")
	ctx := context.Background()

	// One page of products for a brand
	page, err := client.ListProducts(ctx, shelfatlas.ProductListParams{
		BrandIDs: []string{"<brand-uuid>"},
		Limit:    24,
	})
	if err != nil {
		log.Fatal(err)
	}
	for _, p := range page.Data {
		fmt.Println(p.ID, deref(p.CanonicalName))
	}

	// Stores within 5 km of a coordinate
	stores, _ := client.NearestStores(ctx, shelfatlas.NearestParams{Lat: 55.68, Lng: 12.57, RadiusKm: 5})
	_ = stores

	// Walk every page of a listing (range-over-func)
	for product, err := range client.IterProducts(ctx, shelfatlas.ProductListParams{ChainSlug: "netto"}) {
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(product.ID)
	}
}

func deref(s *string) string { if s == nil { return "" }; return *s }

Numeric Price fields are decimal strings (Postgres numeric columns are returned as strings, not numbers) — parse before arithmetic.

Methods

Method Endpoint
ListProducts(ctx, ProductListParams) GET /products
GetProduct(ctx, id) GET /products/:id
ListProductOffers(ctx, id, PageParams) GET /products/:id/offers
ListOffers(ctx, OfferListParams) GET /offers
GetOffer(ctx, id) GET /offers/:id
ListStores(ctx, StoreListParams) GET /stores
NearestStores(ctx, NearestParams) GET /stores (nearest)
GetStore(ctx, id) GET /stores/:id
ListChains(ctx) GET /chains
PriceHistory(ctx, PriceHistoryParams) GET /price-history
IterProducts/IterOffers/IterStores(...) cursor walkers (iter.Seq2)

Configure with options: NewClient(url, key, shelfatlas.WithTimeout(…), shelfatlas.WithHTTPClient(…), shelfatlas.WithMaxAttempts(…), shelfatlas.WithBaseDelay(…)).

Errors

Every failure returns a *CatalogError with a .Code: unauthorized · rate_limited (carries .RetryAfterSec) · invalid_params · not_found · server_error · network_error · invalid_response. GETs retry automatically on 429/5xx (3 attempts, exponential backoff, honouring Retry-After).

var apiErr *shelfatlas.CatalogError
if errors.As(err, &apiErr) && apiErr.Code == shelfatlas.ErrNotFound {
	// handle 404
}

Rate limits & quotas

Free keys: 1,000 requests lifetime, 60 requests/minute. Partner keys: no lifetime cap, 600 requests/minute.

API reference

The full machine-readable contract this client conforms to is published as OpenAPI 3.1 at https://shelfatlas.com/docs/openapi.json. Human docs: https://shelfatlas.com/docs.

Development

go test ./...                                                    # unit + contract
CATALOG_API_KEY=sa_live_… go test -run Smoke -v                  # live smoke

License

MIT

Documentation

Overview

Package shelfatlas is the official Go client for the ShelfAtlas Catalog API — read access to normalised Danish retail catalog data (products, offers, stores, chains, and price history).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CatalogError

type CatalogError struct {
	Code          ErrorCode
	Message       string
	Status        int
	RetryAfterSec float64
}

CatalogError is returned by every client method on failure.

RetryAfterSec is populated from the Retry-After header on a rate_limited (429) response. Callers can type-assert: var e *CatalogError; errors.As(err, &e).

func (*CatalogError) Error

func (e *CatalogError) Error() string

type Chain

type Chain struct {
	ID   string `json:"id"`
	Slug string `json:"slug"`
	Name string `json:"name"`
}

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a ShelfAtlas Catalog API client. Create one with NewClient.

func NewClient

func NewClient(baseURL, apiKey string, opts ...Option) *Client

NewClient returns a client for baseURL (e.g. "https://api.shelfatlas.com") authenticated with a ShelfAtlas API key.

func (*Client) GetOffer

func (c *Client) GetOffer(ctx context.Context, id string) (*Offer, error)

func (*Client) GetProduct

func (c *Client) GetProduct(ctx context.Context, id string) (*Product, error)

func (*Client) GetStore

func (c *Client) GetStore(ctx context.Context, id string) (*Store, error)

func (*Client) IterOffers

func (c *Client) IterOffers(ctx context.Context, p OfferListParams) iter.Seq2[Offer, error]

func (*Client) IterProductOffers

func (c *Client) IterProductOffers(ctx context.Context, productID string, p PageParams) iter.Seq2[Offer, error]

func (*Client) IterProducts

func (c *Client) IterProducts(ctx context.Context, p ProductListParams) iter.Seq2[Product, error]

func (*Client) IterStores

func (c *Client) IterStores(ctx context.Context, p StoreListParams) iter.Seq2[Store, error]

func (*Client) ListChains

func (c *Client) ListChains(ctx context.Context) ([]Chain, error)

func (*Client) ListOffers

func (c *Client) ListOffers(ctx context.Context, p OfferListParams) (*Page[Offer], error)

func (*Client) ListProductOffers

func (c *Client) ListProductOffers(ctx context.Context, productID string, p PageParams) (*Page[Offer], error)

func (*Client) ListProducts

func (c *Client) ListProducts(ctx context.Context, p ProductListParams) (*Page[Product], error)

func (*Client) ListStores

func (c *Client) ListStores(ctx context.Context, p StoreListParams) (*Page[Store], error)

func (*Client) NearestStores

func (c *Client) NearestStores(ctx context.Context, p NearestParams) (*Page[Store], error)

func (*Client) PriceHistory

func (c *Client) PriceHistory(ctx context.Context, p PriceHistoryParams) ([]PriceHistoryPoint, error)

type ErrorCode

type ErrorCode string

ErrorCode mirrors the TypeScript and Python SDKs' error taxonomy so behaviour is consistent across languages.

const (
	ErrUnauthorized    ErrorCode = "unauthorized"
	ErrRateLimited     ErrorCode = "rate_limited"
	ErrInvalidParams   ErrorCode = "invalid_params"
	ErrNotFound        ErrorCode = "not_found"
	ErrServerError     ErrorCode = "server_error"
	ErrNetworkError    ErrorCode = "network_error"
	ErrInvalidResponse ErrorCode = "invalid_response"
)

type NearestParams

type NearestParams struct {
	Lat       float64
	Lng       float64
	RadiusKm  float64
	ChainSlug string
	Limit     int
}

type Offer

type Offer struct {
	ID            string  `json:"id"`
	ChainID       *string `json:"chainId"`
	ProductID     *string `json:"productId"`
	Price         *string `json:"price"`
	Currency      *string `json:"currency"`
	OriginalPrice *string `json:"originalPrice"`
	ValidFrom     *string `json:"validFrom"`
	ValidTo       *string `json:"validTo"`
}

type OfferListParams

type OfferListParams struct {
	ProductID  string
	ProductIDs []string
	ChainSlug  string
	Cursor     string
	Limit      int
}

type Option

type Option func(*Client)

Option configures a Client.

func WithBaseDelay

func WithBaseDelay(d time.Duration) Option

WithBaseDelay sets the exponential-backoff base delay.

func WithHTTPClient

func WithHTTPClient(h *http.Client) Option

WithHTTPClient sets the underlying *http.Client (e.g. for custom transports).

func WithMaxAttempts

func WithMaxAttempts(n int) Option

WithMaxAttempts sets the total attempts (including the first) for retryable GETs.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the per-request timeout on the default http client.

type Page

type Page[T any] struct {
	Data       []T
	Pagination *Pagination
}

Page is one page of a cursor-paginated listing.

type PageParams

type PageParams struct {
	Cursor string
	Limit  int
}

type Pagination

type Pagination struct {
	Limit  int     `json:"limit"`
	Cursor *string `json:"cursor"`
}

type PriceHistoryParams

type PriceHistoryParams struct {
	ProductIDs []string
	Days       int
}

type PriceHistoryPoint

type PriceHistoryPoint struct {
	ProductID     string `json:"productId"`
	Date          string `json:"date"`
	MinPriceCents int    `json:"minPriceCents"`
	ChainSlug     string `json:"chainSlug"`
}

type Product

type Product struct {
	ID                string  `json:"id"`
	CanonicalName     *string `json:"canonicalName"`
	BrandID           *string `json:"brandId"`
	PrimaryCategoryID *string `json:"primaryCategoryId"`
	ImageURL          *string `json:"imageUrl"`
}

type ProductListParams

type ProductListParams struct {
	ChainSlug   string
	BrandIDs    []string
	CategoryIDs []string
	IDs         []string
	ExcludeIDs  []string
	Cursor      string
	Limit       int
}

type Store

type Store struct {
	ID           string         `json:"id"`
	Name         string         `json:"name"`
	ChainSlug    string         `json:"chainSlug"`
	ChainName    string         `json:"chainName"`
	Address      string         `json:"address"`
	City         string         `json:"city"`
	PostalCode   *string        `json:"postalCode"`
	Lat          float64        `json:"lat"`
	Lng          float64        `json:"lng"`
	OpeningHours map[string]any `json:"openingHours"`
	Timezone     string         `json:"timezone"`
}

type StoreListParams

type StoreListParams struct {
	ChainSlug string
	Limit     int
}

Jump to

Keyboard shortcuts

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