Documentation
¶
Overview ¶
Package labelzoom is the official Go client for the LabelZoom API.
LabelZoom converts barcode labels between printer languages (ZPL, EPL, TSPL, DPL), LabelZoom's own XML/JSON model, PDF, and raster images. Almost everything the API does happens at one endpoint:
POST https://api.labelzoom.com/api/v2/convert/{sourceFormat}/to/{targetFormat}
Authentication is optional. Without a credential the API serves a free tier: watermarked output, the first label only, a 1 MB request cap, and no multi-page, JSON-target or image-to-image conversion. Constructing a Client with no key is therefore a supported, tested path rather than an error.
client, err := labelzoom.New(labelzoom.WithAPIKey("lz_live_..."))
if err != nil {
return err
}
result, err := client.Convert(ctx, labelzoom.ConvertRequest{
From: labelzoom.SourceZPL,
To: labelzoom.TargetPNG,
Body: []byte("^XA^FO20,20^A0N,28^FDhello^FS^XZ"),
})
if err != nil {
return err
}
os.WriteFile("label.png", result.Bytes, 0o644)
The behaviour of every LabelZoom SDK is specified in docs/API_CONTRACT.md and checked by the shared fixtures in conformance/, which this package's test suite executes in full.
Index ¶
- Constants
- Variables
- func Ptr[T any](v T) *T
- type APIError
- type BadRequestError
- type Client
- type ColorMode
- type ConvertRequest
- type DataRecord
- type ForbiddenError
- type LabelSize
- type NotFoundError
- type Option
- func WithAPIKey(apiKey string) Option
- func WithAnonymous() Option
- func WithBaseURL(baseURL string) Option
- func WithEnvLookup(lookup func(string) (string, bool)) Option
- func WithHTTPClient(httpClient *http.Client) Option
- func WithMaxRetries(maxRetries int) Option
- func WithSleeper(sleep func(time.Duration)) Option
- func WithTimeout(timeout time.Duration) Option
- func WithUserAgentSuffix(suffix string) Option
- func WithoutJitter() Option
- type Options
- type PDFConversionMode
- type PDFOptions
- type PayloadTooLargeError
- type Position
- type RateLimitedError
- type Result
- type ServerError
- type SourceFormat
- type TargetFormat
- type UnauthorizedError
- type ValidationError
- type ZPLImageCompression
- type ZPLOptions
Constants ¶
const APIKeyEnvVar = "LABELZOOM_API_KEY"
APIKeyEnvVar is the environment variable consulted when no credential is configured.
const DefaultBaseURL = "https://api.labelzoom.com"
DefaultBaseURL is the production API host.
const Version = "1.0.0"
Version is the SDK version. It appears in the User-Agent of every request, so the release workflow asserts that it matches the `go/vX.Y.Z` tag being published.
Variables ¶
var ErrValidation = errValidation
ErrValidation matches any ValidationError under errors.Is, for callers that only need to tell a local rejection from a server response.
Functions ¶
func Ptr ¶
func Ptr[T any](v T) *T
Ptr returns a pointer to v, for setting an Options field.
Options are pointers so that "not set" is distinguishable from a zero value the caller meant: Watermark: Ptr(false) and PageNumber: Ptr(0) are both sent, while an omitted field is not sent at all. The SDK never substitutes a default of its own, so a change to a server default reaches you without an SDK upgrade.
Type inference follows the literal, so a float64 field wants Ptr(4.0), not Ptr(4).
Types ¶
type APIError ¶
type APIError struct {
// Status is the HTTP status code the API returned.
Status int
// Message is the human-readable detail, derived from the body and capped at 512
// characters.
Message string
// RequestID is the X-LZ-Request-Id response header, when the server sent one. Quote it
// to LabelZoom support -- it identifies the exact request server-side.
RequestID string
// RawBody is the response body, untruncated.
RawBody string
}
APIError is the payload every error the LabelZoom API returns carries.
It is embedded in the per-status types below, each of which unwraps to it, so both of these work:
var rateLimited *labelzoom.RateLimitedError
if errors.As(err, &rateLimited) { time.Sleep(rateLimited.RetryAfter()) }
var apiErr *labelzoom.APIError
if errors.As(err, &apiErr) { log.Printf("request %s failed: %s", apiErr.RequestID, apiErr.Message) }
ValidationError deliberately does not unwrap to APIError: it is a bug in the calling code, not a server response, so code catching API errors to implement a fallback must not swallow it.
type BadRequestError ¶
type BadRequestError struct{ APIError }
BadRequestError is HTTP 400: the request was malformed or the conversion path is invalid.
func (*BadRequestError) Unwrap ¶
func (e *BadRequestError) Unwrap() error
Unwrap exposes the embedded APIError to errors.As.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client converts labels through the LabelZoom API. It is safe for concurrent use.
func New ¶
New builds a client.
Every argument is optional: with no options at all the client reads LABELZOOM_API_KEY from the environment, falls back to the anonymous free tier if it is unset, and talks to DefaultBaseURL.
func (*Client) Convert ¶
Convert runs one conversion.
On a non-2xx response it returns one of the typed errors in this package -- see APIError. A request rejected before it leaves the process returns a ValidationError, which does not unwrap to APIError.
func (*Client) IsAuthenticated ¶
IsAuthenticated reports whether a credential was resolved. False means requests go out on the anonymous free tier, which is a supported mode rather than an error.
type ColorMode ¶
type ColorMode string
ColorMode selects how colour is reduced when rasterizing. Server default GRAYSCALE.
type ConvertRequest ¶
type ConvertRequest struct {
// From is the format of Body.
From SourceFormat
// To is the format to produce.
To TargetFormat
// Body is the document. For [SourceURL] it is the URL to fetch, as text.
Body []byte
// Options are the conversion parameters. Nil sends none, which is a bare URL with no
// query string at all.
Options *Options
// AsBase64Text sends Body as base64 text/plain rather than the source's own media
// type. Only the binary sources (PDF and the raster images) support it.
AsBase64Text bool
}
ConvertRequest describes one conversion.
Go gets a request struct rather than the fluent chain the other SDKs expose: a chain in Go has to either panic or defer its errors to a terminal Do(), and both are un-Go. The wire behaviour is identical -- only the ergonomics differ.
type DataRecord ¶
DataRecord holds one label's variable-field values, keyed by field name.
type ForbiddenError ¶
type ForbiddenError struct {
APIError
// IsPaidFeature is true when this 403 is a paywall rather than a permissions problem --
// "JSON export is a paid feature" and friends. It is by far the most common
// anonymous-tier failure, so it gets a flag instead of leaving callers matching strings.
IsPaidFeature bool
}
ForbiddenError is HTTP 403: the credential is valid but not entitled to this operation.
func (*ForbiddenError) Unwrap ¶
func (e *ForbiddenError) Unwrap() error
Unwrap exposes the embedded APIError to errors.As.
type LabelSize ¶
type LabelSize struct {
Width *float64 `json:"width,omitempty"`
Height *float64 `json:"height,omitempty"`
}
LabelSize is the media size, in INCHES -- not dots, and not millimetres.
Omitting it entirely is meaningful: it asks the server to detect the size. That is why the fields are pointers and why an unset LabelSize emits no "label" key at all.
type NotFoundError ¶
type NotFoundError struct{ APIError }
NotFoundError is HTTP 404: the conversion path does not exist.
func (*NotFoundError) Unwrap ¶
func (e *NotFoundError) Unwrap() error
Unwrap exposes the embedded APIError to errors.As.
type Option ¶
type Option func(*config)
Option configures a Client. See New.
func WithAPIKey ¶
WithAPIKey sets the credential: an lz_live_/lz_test_ key or a JWT.
Passing an empty string forces anonymous mode and suppresses the LABELZOOM_API_KEY fallback, which is what you want when a config file may or may not carry a key and you do not want the environment deciding. See also WithAnonymous.
Without this option the client reads LABELZOOM_API_KEY from the environment.
func WithAnonymous ¶
func WithAnonymous() Option
WithAnonymous forces the free tier: no credential, and no environment fallback.
The anonymous tier is watermarked, converts the first label only, caps requests at 1 MB, and rejects multi-page, JSON-target and image-to-image conversions.
func WithBaseURL ¶
WithBaseURL overrides the API host. A path prefix is preserved, so a reverse proxy at https://proxy.example.com/labelzoom works.
func WithEnvLookup ¶
WithEnvLookup replaces the environment lookup used to find LABELZOOM_API_KEY. Injecting it keeps a developer's real key out of a test's outcome.
func WithHTTPClient ¶
WithHTTPClient substitutes the http.Client used for every request. This is the seam to stub in tests -- give it a Transport that returns canned responses and no socket is ever opened.
func WithMaxRetries ¶
WithMaxRetries sets the number of retries after the initial attempt. Defaults to 2, for 3 attempts in total. Zero disables retrying.
func WithSleeper ¶
WithSleeper replaces the delay between retries. Substitute a recording no-op in tests so the retry paths cost no wall-clock time.
func WithTimeout ¶
WithTimeout sets a per-attempt timeout. Zero, the default, means no client-side timeout beyond whatever the context and the http.Client impose.
func WithUserAgentSuffix ¶
WithUserAgentSuffix appends a token to the SDK's own User-Agent.
It is appended, never prepended: the server parses a leading "LabelZoomStudio/" as a Studio version and silently changes PDF handling for versions <= 1.8.2.
func WithoutJitter ¶
func WithoutJitter() Option
WithoutJitter makes the retry backoff exactly 1s, 2s, 4s instead of a random duration up to that bound. For deterministic tests; leave jitter on in production, where it is what stops a fleet retrying in lockstep.
type Options ¶
type Options struct {
// DPI is the output resolution. Server default 203.
DPI *int
// Rotation is degrees clockwise and must be a multiple of 90. Server default 0.
Rotation *int
// Scaling is a percentage. Server default 100.
Scaling *float64
// ColorMode selects colour reduction. Server default GRAYSCALE.
ColorMode *ColorMode
// Darkness is a luminance threshold from 0 to 100. Server default 70.
Darkness *int
// Position is the pixel offset of the extracted region.
Position *Position
// Watermark is forced on for the anonymous free tier regardless of what you set.
Watermark *bool
// Dialect selects a printer dialect, e.g. "moca". Requires a paid license.
Dialect *string
// Data holds the variable-field values, one record per output label.
//
// Accepts a [DataRecord], a []DataRecord, or any JSON-shaped equivalent. A single
// record is wrapped into a one-element array rather than rejected, because one record
// means one label. An element that is not an object is a local validation error.
Data any
// Label is the media size in INCHES. Omit it to have the server detect the size.
Label *LabelSize
// PDF configures how a PDF source is read.
PDF *PDFOptions
// ZPL configures ZPL output.
ZPL *ZPLOptions
// Extra carries anything this SDK does not model yet. Unknown keys are ignored
// server-side, so it is a safe forward-compatibility escape hatch. Keys here are
// merged at the top level of the params object and override the fields above.
Extra map[string]any
// RawQuery adds query parameters alongside params, for the rare case that a new API
// feature is not carried inside params at all. Prefer Extra: everything the conversion
// endpoint takes today travels in params.
RawQuery map[string]string
}
Options are the conversion parameters, in the shape the API expects.
Every field is optional and only the ones you set are sent. The SDK never fills in a client-side default, which is why the scalars are pointers -- see [Int], [Float64], [Bool] and [String]. Setting nothing at all produces a bare URL with no query string.
type PDFConversionMode ¶
type PDFConversionMode string
PDFConversionMode selects how a PDF source is interpreted. Server default IMAGE.
const ( // PDFConversionModeImage rasterizes the page. PDFConversionModeImage PDFConversionMode = "IMAGE" // PDFConversionModeNative extracts the page's text and vectors. PDFConversionModeNative PDFConversionMode = "NATIVE" )
The PDF conversion modes the API accepts.
type PDFOptions ¶
type PDFOptions struct {
// ConversionMode selects rasterizing versus native extraction. Server default IMAGE.
ConversionMode *PDFConversionMode `json:"conversionMode,omitempty"`
// PageNumber is ZERO-BASED. Omit it to convert every page.
PageNumber *int `json:"pageNumber,omitempty"`
}
PDFOptions configures how a PDF source is read.
type PayloadTooLargeError ¶
type PayloadTooLargeError struct{ APIError }
PayloadTooLargeError is HTTP 413: the body exceeded the tier's limit, which is 1 MB on the anonymous free tier.
func (*PayloadTooLargeError) Unwrap ¶
func (e *PayloadTooLargeError) Unwrap() error
Unwrap exposes the embedded APIError to errors.As.
type RateLimitedError ¶
type RateLimitedError struct {
APIError
// RetryAfterSeconds is the Retry-After header, when the server sent one. The client
// already honours it during its own retries; this exposes it for callers doing theirs.
RetryAfterSeconds *float64
}
RateLimitedError is HTTP 429.
func (*RateLimitedError) Unwrap ¶
func (e *RateLimitedError) Unwrap() error
Unwrap exposes the embedded APIError to errors.As.
type Result ¶
type Result struct {
// Bytes is the response body, exactly as the server sent it.
Bytes []byte
// ContentType is the response Content-Type header, if any.
ContentType string
// Status is the HTTP status code, always 2xx here.
Status int
// RequestID is the X-LZ-Request-Id response header, when the server sent one. The
// support handle.
RequestID string
}
Result is the outcome of a successful conversion.
Bytes is authoritative. PDF, PNG, BMP, GIF and JPEG targets are binary, so treating the response as a string would silently corrupt five of the eleven targets -- and EPL and TSPL reach the same hazard through a text/plain response, because their GW and BITMAP commands inline a raw 1-bpp payload.
type ServerError ¶
type ServerError struct{ APIError }
ServerError is HTTP 5xx. Retried automatically before it surfaces.
func (*ServerError) Unwrap ¶
func (e *ServerError) Unwrap() error
Unwrap exposes the embedded APIError to errors.As.
type SourceFormat ¶
type SourceFormat string
SourceFormat is the format of the document being converted.
It is a distinct type from TargetFormat, and the two sets are not the same: JPG and URL are source-only. JPG is an input spelling that normalizes to JPEG on the wire, and URL is an instruction to the server to go fetch a document rather than a format at all. Passing a SourceFormat where a TargetFormat is wanted does not compile.
const ( SourceZPL SourceFormat = "zpl" SourceEPL SourceFormat = "epl" SourceTSPL SourceFormat = "tspl" SourceDPL SourceFormat = "dpl" SourceXML SourceFormat = "xml" SourceJSON SourceFormat = "json" SourcePDF SourceFormat = "pdf" SourcePNG SourceFormat = "png" SourceBMP SourceFormat = "bmp" SourceGIF SourceFormat = "gif" SourceJPEG SourceFormat = "jpeg" // SourceJPG is an alias for SourceJPEG and is sent as "jpeg". SourceJPG SourceFormat = "jpg" // SourceURL has the server fetch a document and convert what it finds. The request body // is the URL. Validate it first if it came from untrusted input: the fetch happens // server-side, from LabelZoom's network. SourceURL SourceFormat = "url" )
The twelve document formats, plus URL.
func SourceFormats ¶
func SourceFormats() []SourceFormat
SourceFormats lists every accepted source, in the contract's order.
type TargetFormat ¶
type TargetFormat string
TargetFormat is the format to convert into.
There is no TargetURL: URL is a fetch instruction, not an output format. The printer languages round-trip -- EPL, TSPL and DPL are targets as well as sources.
const ( TargetZPL TargetFormat = "zpl" // TargetEPL output can inline raw binary (the GW command); read Result.Bytes rather // than Result.Text when a label might carry graphics. TargetEPL TargetFormat = "epl" // TargetTSPL output can inline raw binary (the BITMAP command); read Result.Bytes // rather than Result.Text when a label might carry graphics. TargetTSPL TargetFormat = "tspl" TargetDPL TargetFormat = "dpl" TargetXML TargetFormat = "xml" TargetJSON TargetFormat = "json" TargetPDF TargetFormat = "pdf" TargetPNG TargetFormat = "png" TargetBMP TargetFormat = "bmp" TargetGIF TargetFormat = "gif" TargetJPEG TargetFormat = "jpeg" )
The eleven output formats.
func TargetFormats ¶
func TargetFormats() []TargetFormat
TargetFormats lists every accepted target, in the contract's order.
type UnauthorizedError ¶
UnauthorizedError is HTTP 401: the supplied credential was rejected.
func (*UnauthorizedError) Unwrap ¶
func (e *UnauthorizedError) Unwrap() error
Unwrap exposes the embedded APIError to errors.As.
type ValidationError ¶
type ValidationError struct {
// Parameter is the conversion parameter at fault, named as it appears on the wire.
Parameter string
Message string
}
ValidationError reports a request rejected locally, before any network call.
Deliberately not an APIError: it carries no status, it is never retried, and it does not unwrap to APIError, so a caller inspecting API errors will not mistake it for one.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
func (*ValidationError) Is ¶
func (e *ValidationError) Is(target error) bool
Is lets errors.Is(err, ErrValidation) match any ValidationError.
type ZPLImageCompression ¶
type ZPLImageCompression string
ZPLImageCompression selects the encoding of images embedded in ZPL output. Server default Z64.
const ( ZPLImageCompressionZ64 ZPLImageCompression = "Z64" ZPLImageCompressionCompressedHex ZPLImageCompression = "COMPRESSED_HEX" )
The ZPL image compressions the API accepts.
type ZPLOptions ¶
type ZPLOptions struct {
// CommandsToIgnore drops the named commands from the output, e.g. []string{"^PQ"}.
CommandsToIgnore []string `json:"commandsToIgnore,omitempty"`
// ImageCompression selects the encoding of embedded images. Server default Z64.
ImageCompression *ZPLImageCompression `json:"imageCompression,omitempty"`
}
ZPLOptions configures ZPL output.
