package catalog
import "github.com/weswhet/applevpp/catalog"
Package catalog provides a Go client for Apple's Apps and Books for Organizations API.
The catalog API is separate from Apple's VPP management API and is intended for storefront-aware metadata retrieval. This package includes:
- typed app, book, search, and storefront queries
- owned app and owned book metadata lookups for sToken-authenticated calls
- ES256 developer-token generation helpers
- forward-compatible response models that preserve unknown JSON fields
The main entry point is NewClient. Runnable usage snippets are available in example_test.go.
Index
- Variables
- func GenerateDeveloperToken(keyID, teamID string, privateKeyPEM []byte, opts GenerateDeveloperTokenOptions) (string, error)
- type APIError
- type AllStorefrontsQuery
- type App
- type AppAttributes
- type AppPlatformAttributes
- type AppsResponse
- type Artwork
- type Book
- type BookAttributes
- type BooksResponse
- type CatalogAppQuery
- type CatalogAppsQuery
- type CatalogBookQuery
- type CatalogBooksQuery
-
type Client
- func NewClient(developerToken string, opts Options) (*Client, error)
- func (c *Client) GetAllStorefronts(ctx context.Context, query AllStorefrontsQuery) (*StorefrontsResponse, error)
- func (c *Client) GetApp(ctx context.Context, storefront, id string, query CatalogAppQuery) (*AppsResponse, error)
- func (c *Client) GetApps(ctx context.Context, storefront string, query CatalogAppsQuery) (*AppsResponse, error)
- func (c *Client) GetBook(ctx context.Context, storefront, id string, query CatalogBookQuery) (*BooksResponse, error)
- func (c *Client) GetBooks(ctx context.Context, storefront string, query CatalogBooksQuery) (*BooksResponse, error)
- func (c *Client) GetOwnedApps(ctx context.Context, storefront string, query OwnedAppsQuery) (*ResourceCollectionResponse, error)
- func (c *Client) GetOwnedBooks(ctx context.Context, storefront string, query OwnedBooksQuery) (*ResourceCollectionResponse, error)
- func (c *Client) GetStorefront(ctx context.Context, id string, query StorefrontQuery) (*StorefrontsResponse, error)
- func (c *Client) GetStorefronts(ctx context.Context, query StorefrontsQuery) (*StorefrontsResponse, error)
- func (c *Client) Search(ctx context.Context, storefront string, query SearchQuery) (*ResultsResponse, error)
- type ContentRating
- type DescriptionAttribute
- type Error
- type ErrorsResponse
- type GenerateDeveloperTokenOptions
- type Offer
- type OfferAsset
- type OfferVersion
- type Options
- type Organization
- type OwnedAppsQuery
- type OwnedBooksQuery
- type Platform
- type Relationship
- type Resource
- type ResourceCollectionResponse
- type ResultsResponse
- type ScopedInt
- type ScopedValues
- type SearchQuery
- type SearchType
- type Storefront
- type StorefrontAttributes
- type StorefrontQuery
- type StorefrontsQuery
- type StorefrontsResponse
- type UnauthorizedResponse
- type UserRating
Examples
Variables
var ErrNoDeveloperToken = errors.New("catalog: developer token is required")
ErrNoDeveloperToken indicates that a catalog endpoint was called without a developer token.
var ErrNoPlatform = errors.New("catalog: platform is required")
ErrNoPlatform indicates that a catalog request omitted Apple's required platform query parameter.
var ErrNoResourceID = errors.New("catalog: resource ID is required")
ErrNoResourceID indicates that a single-resource catalog request omitted the required resource identifier.
var ErrNoSToken = errors.New("catalog: sToken is required for this endpoint")
ErrNoSToken indicates that an sToken-authenticated endpoint was called without an sToken cookie value.
var ErrNoStorefront = errors.New("catalog: storefront is required")
ErrNoStorefront indicates that a catalog request omitted a required storefront path parameter.
Functions
func GenerateDeveloperToken
func GenerateDeveloperToken(keyID, teamID string, privateKeyPEM []byte, opts GenerateDeveloperTokenOptions) (string, error)
GenerateDeveloperToken creates an ES256 JWT that can be used with Apple's
Apps and Books for Organizations catalog API.
Output:Example
privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
der, _ := x509.MarshalECPrivateKey(privateKey)
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: der})
token, _ := GenerateDeveloperToken("ABC123DEFG", "TEAM123456", keyPEM, GenerateDeveloperTokenOptions{
IssuedAt: time.Unix(1700000000, 0).UTC(),
ExpiresAt: time.Unix(1700003600, 0).UTC(),
})
fmt.Println(strings.Count(token, "."))
2
Types
type APIError
type APIError struct { StatusCode int Errors []Error RetryAfter time.Duration Body []byte }
APIError represents an HTTP error returned by Apple's catalog API.
func (*APIError) Error
func (e *APIError) Error() string
type AllStorefrontsQuery
type AllStorefrontsQuery struct { Extend ScopedValues Include ScopedValues Language string Limit ScopedInt Offset string Platform Platform Relate ScopedValues }
AllStorefrontsQuery filters the paginated storefront listing endpoint.
type App
type App struct { Attributes AppAttributes `json:"attributes,omitempty"` Href string `json:"href"` ID string `json:"id"` Relationships map[string]Relationship `json:"relationships,omitempty"` Type string `json:"type"` }
type AppAttributes
type AppAttributes struct { ArtistName string `json:"artistName,omitempty"` Artwork *Artwork `json:"artwork,omitempty"` ContentRatingsBySystem map[string]ContentRating `json:"contentRatingsBySystem,omitempty"` Description *DescriptionAttribute `json:"description,omitempty"` DeviceFamilies []string `json:"deviceFamilies,omitempty"` GenreDisplayName string `json:"genreDisplayName,omitempty"` GenreNames []string `json:"genreNames,omitempty"` HasEula bool `json:"hasEula,omitempty"` IsB2BCustomApp bool `json:"isB2BCustomApp,omitempty"` IsFirstPartyHideableApp bool `json:"isFirstPartyHideableApp,omitempty"` IsIOSBinaryMacOSCompatible bool `json:"isIOSBinaryMacOSCompatible,omitempty"` IsVppDeviceBasedLicensingEnabled bool `json:"isVppDeviceBasedLicensingEnabled,omitempty"` Name string `json:"name,omitempty"` Offers []Offer `json:"offers,omitempty"` PlatformAttributes map[string]AppPlatformAttributes `json:"platformAttributes,omitempty"` SupportsDeviceSharing bool `json:"supportsDeviceSharing,omitempty"` URL string `json:"url,omitempty"` UserRating *UserRating `json:"userRating,omitempty"` UsesClassKit bool `json:"usesClassKit,omitempty"` Unknown map[string]json.RawMessage `json:"-"` }
func (*AppAttributes) UnmarshalJSON
func (a *AppAttributes) UnmarshalJSON(data []byte) error
type AppPlatformAttributes
type AppPlatformAttributes struct { Artwork *Artwork `json:"artwork,omitempty"` BundleID string `json:"bundleId,omitempty"` ExternalVersionID int64 `json:"externalVersionId,omitempty"` IsVisionOSCompatible bool `json:"isVisionOSCompatible,omitempty"` MinimumMacOSVersion string `json:"minimumMacOSVersion,omitempty"` MinimumOSVersion string `json:"minimumOSVersion,omitempty"` MinimumVisionOSVersion string `json:"minimumVisionOSVersion,omitempty"` RequiredCapabilities string `json:"requiredCapabilities,omitempty"` RequiredCapabilitiesForRealityDevice string `json:"requiredCapabilitiesForRealityDevice,omitempty"` Seller string `json:"seller,omitempty"` Subtitle string `json:"subtitle,omitempty"` Unknown map[string]json.RawMessage `json:"-"` }
func (*AppPlatformAttributes) UnmarshalJSON
func (a *AppPlatformAttributes) UnmarshalJSON(data []byte) error
type AppsResponse
type AppsResponse struct { Data []App `json:"data"` }
type Artwork
type Artwork struct { AssetToken string `json:"assetToken,omitempty"` BGColor string `json:"bgColor,omitempty"` Gradient json.RawMessage `json:"gradient,omitempty"` HasP3 bool `json:"hasP3,omitempty"` Height float64 `json:"height"` PictureFileType string `json:"pictureFileType,omitempty"` SupportsLayeredImage bool `json:"supportsLayeredImage,omitempty"` TextColor1 string `json:"textColor1,omitempty"` TextColor2 string `json:"textColor2,omitempty"` TextColor3 string `json:"textColor3,omitempty"` TextColor4 string `json:"textColor4,omitempty"` URL string `json:"url"` Width float64 `json:"width"` Unknown map[string]json.RawMessage `json:"-"` }
func (*Artwork) UnmarshalJSON
func (a *Artwork) UnmarshalJSON(data []byte) error
type Book
type Book struct { Attributes BookAttributes `json:"attributes,omitempty"` Href string `json:"href"` ID string `json:"id"` Relationships map[string]Relationship `json:"relationships,omitempty"` Type string `json:"type"` }
type BookAttributes
type BookAttributes struct { ArtistName string `json:"artistName,omitempty"` Artwork *Artwork `json:"artwork,omitempty"` GenreNames []string `json:"genreNames,omitempty"` ISBN string `json:"isbn,omitempty"` Name string `json:"name,omitempty"` Offers []Offer `json:"offers,omitempty"` URL string `json:"url,omitempty"` UserRating *UserRating `json:"userRating,omitempty"` Unknown map[string]json.RawMessage `json:"-"` }
func (*BookAttributes) UnmarshalJSON
func (b *BookAttributes) UnmarshalJSON(data []byte) error
type BooksResponse
type BooksResponse struct { Data []Book `json:"data"` }
type CatalogAppQuery
type CatalogAppQuery struct { AdditionalPlatforms []Platform Extend ScopedValues Include ScopedValues Language string Platform Platform Relate ScopedValues }
CatalogAppQuery filters metadata lookup for a single app.
type CatalogAppsQuery
type CatalogAppsQuery struct { AdditionalPlatforms []Platform Extend ScopedValues IDs []string Include ScopedValues Language string Platform Platform Relate ScopedValues }
CatalogAppsQuery filters metadata lookup for multiple apps.
func (CatalogAppsQuery) CatalogAppQuery
func (q CatalogAppsQuery) CatalogAppQuery() CatalogAppQuery
type CatalogBookQuery
type CatalogBookQuery struct { AdditionalPlatforms []Platform Include ScopedValues Language string Platform Platform Relate ScopedValues }
CatalogBookQuery filters metadata lookup for a single book.
type CatalogBooksQuery
type CatalogBooksQuery struct { AdditionalPlatforms []Platform IDs []string Include ScopedValues Language string Platform Platform Relate ScopedValues }
CatalogBooksQuery filters metadata lookup for multiple books.
func (CatalogBooksQuery) CatalogBookQuery
func (q CatalogBooksQuery) CatalogBookQuery() CatalogBookQuery
type Client
type Client struct { // contains filtered or unexported fields }
Client wraps Apple's Apps and Books for Organizations catalog API.
func NewClient
func NewClient(developerToken string, opts Options) (*Client, error)
NewClient constructs a catalog client.
The developer token may be provided either as the first argument or through Options.DeveloperToken.
func (*Client) GetAllStorefronts
func (c *Client) GetAllStorefronts(ctx context.Context, query AllStorefrontsQuery) (*StorefrontsResponse, error)
GetAllStorefronts returns a page of storefronts using Apple's paginated storefront listing endpoint.
func (*Client) GetApp
func (c *Client) GetApp(ctx context.Context, storefront, id string, query CatalogAppQuery) (*AppsResponse, error)
GetApp returns metadata for a single app in a storefront.
Output:Example
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_ = json.NewEncoder(w).Encode(AppsResponse{
Data: []App{{ID: "623592465", Type: "apps", Href: "/v1/catalog/us/apps/623592465"}},
})
}))
defer server.Close()
client, _ := NewClient("developer-token", Options{BaseURL: server.URL})
resp, _ := client.GetApp(context.Background(), "us", "623592465", CatalogAppQuery{
Platform: PlatformIPhone,
})
fmt.Println(resp.Data[0].ID)
623592465
func (*Client) GetApps
func (c *Client) GetApps(ctx context.Context, storefront string, query CatalogAppsQuery) (*AppsResponse, error)
GetApps returns metadata for multiple apps in a storefront.
func (*Client) GetBook
func (c *Client) GetBook(ctx context.Context, storefront, id string, query CatalogBookQuery) (*BooksResponse, error)
GetBook returns metadata for a single book in a storefront.
func (*Client) GetBooks
func (c *Client) GetBooks(ctx context.Context, storefront string, query CatalogBooksQuery) (*BooksResponse, error)
GetBooks returns metadata for multiple books in a storefront.
func (*Client) GetOwnedApps
func (c *Client) GetOwnedApps(ctx context.Context, storefront string, query OwnedAppsQuery) (*ResourceCollectionResponse, error)
GetOwnedApps returns the apps visible to the current organization for the supplied storefront and sToken.
func (*Client) GetOwnedBooks
func (c *Client) GetOwnedBooks(ctx context.Context, storefront string, query OwnedBooksQuery) (*ResourceCollectionResponse, error)
GetOwnedBooks returns the books visible to the current organization for the supplied storefront and sToken.
func (*Client) GetStorefront
func (c *Client) GetStorefront(ctx context.Context, id string, query StorefrontQuery) (*StorefrontsResponse, error)
GetStorefront returns metadata for a single storefront.
func (*Client) GetStorefronts
func (c *Client) GetStorefronts(ctx context.Context, query StorefrontsQuery) (*StorefrontsResponse, error)
GetStorefronts returns metadata for specific storefront IDs.
func (*Client) Search
func (c *Client) Search(ctx context.Context, storefront string, query SearchQuery) (*ResultsResponse, error)
Search runs a storefront catalog search for apps or books.
Output:Example
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_ = json.NewEncoder(w).Encode(ResultsResponse{
Results: map[string][]Resource{
"apps": {{
ID: "623592465",
Type: "apps",
}},
},
})
}))
defer server.Close()
client, _ := NewClient("developer-token", Options{BaseURL: server.URL})
resp, _ := client.Search(context.Background(), "us", SearchQuery{
Platform: PlatformIPhone,
Term: "Numbers",
Types: []SearchType{SearchTypeApps},
})
fmt.Println(len(resp.Results["apps"]))
1
type ContentRating
type ContentRating struct { Name string `json:"name,omitempty"` Value int `json:"value,omitempty"` Rank int `json:"rank,omitempty"` Advisories []string `json:"advisories,omitempty"` }
type DescriptionAttribute
type DescriptionAttribute struct { Short string `json:"short,omitempty"` Standard string `json:"standard"` }
type Error
type Error struct { Code string `json:"code"` Detail string `json:"detail,omitempty"` ID string `json:"id"` Source json.RawMessage `json:"source,omitempty"` Status string `json:"status"` Title string `json:"title"` }
type ErrorsResponse
type ErrorsResponse struct { Errors []Error `json:"errors"` }
type GenerateDeveloperTokenOptions
type GenerateDeveloperTokenOptions struct { IssuedAt time.Time ExpiresAt time.Time Origins []string }
GenerateDeveloperTokenOptions controls the issued-at, expiration, and origin claims embedded in a developer token.
type Offer
type Offer struct { ActionText map[string]string `json:"actionText,omitempty"` Assets []OfferAsset `json:"assets,omitempty"` BuyParams string `json:"buyParams,omitempty"` CurrencyCode string `json:"currencyCode,omitempty"` Price float64 `json:"price,omitempty"` PriceFormatted string `json:"priceFormatted,omitempty"` PricePerUnit float64 `json:"pricePerUnit,omitempty"` PricePerUnitFormatted string `json:"pricePerUnitFormatted,omitempty"` Quantity int `json:"quantity,omitempty"` Type string `json:"type,omitempty"` Version *OfferVersion `json:"version,omitempty"` Unknown map[string]json.RawMessage `json:"-"` }
func (*Offer) UnmarshalJSON
func (o *Offer) UnmarshalJSON(data []byte) error
type OfferAsset
type OfferAsset struct { Flavor string `json:"flavor,omitempty"` Size int64 `json:"size,omitempty"` }
type OfferVersion
type OfferVersion struct { Display string `json:"display,omitempty"` ExternalID int64 `json:"externalId,omitempty"` }
type Options
type Options struct { BaseURL string HTTPClient *http.Client Organization Organization DeveloperToken string SToken string UserAgent string Now func() time.Time }
Options configures a catalog client.
type Organization
type Organization string
Organization selects the Apple catalog host family.
const ( OrganizationEnterprise Organization = "enterprise" OrganizationEducation Organization = "education" )
type OwnedAppsQuery
type OwnedAppsQuery struct { AdditionalPlatforms []Platform Extend ScopedValues IDs []string Language string Platform Platform }
OwnedAppsQuery filters sToken-authenticated owned app lookups.
type OwnedBooksQuery
type OwnedBooksQuery struct { AdditionalPlatforms []Platform IDs []string Language string Platform Platform }
OwnedBooksQuery filters sToken-authenticated owned book lookups.
type Platform
type Platform string
Platform identifies the target Apple platform for catalog queries.
const ( PlatformAppleTV Platform = "appletv" PlatformIPad Platform = "ipad" PlatformIPhone Platform = "iphone" PlatformMac Platform = "mac" PlatformRealityDevice Platform = "realityDevice" PlatformWeb Platform = "web" )
type Relationship
type Relationship struct { Data []Resource `json:"data,omitempty"` Href string `json:"href,omitempty"` Meta map[string]json.RawMessage `json:"meta,omitempty"` Next string `json:"next,omitempty"` Unknown map[string]json.RawMessage `json:"-"` }
func (*Relationship) UnmarshalJSON
func (r *Relationship) UnmarshalJSON(data []byte) error
type Resource
type Resource struct { Attributes json.RawMessage `json:"attributes,omitempty"` Href string `json:"href,omitempty"` ID string `json:"id"` Meta map[string]json.RawMessage `json:"meta,omitempty"` Relationships map[string]Relationship `json:"relationships,omitempty"` Type string `json:"type"` Views map[string]json.RawMessage `json:"views,omitempty"` Unknown map[string]json.RawMessage `json:"-"` }
func (*Resource) UnmarshalJSON
func (r *Resource) UnmarshalJSON(data []byte) error
type ResourceCollectionResponse
type ResourceCollectionResponse struct { Data []Resource `json:"data"` }
type ResultsResponse
type ResultsResponse struct { Results map[string][]Resource `json:"results"` }
type ScopedInt
type ScopedInt struct { Default *int ByScope map[string]int }
type ScopedValues
type ScopedValues struct { Default []string ByScope map[string][]string }
type SearchQuery
type SearchQuery struct { AdditionalPlatforms []Platform Extend ScopedValues Filter ScopedValues Language string Platform Platform Term string Types []SearchType }
SearchQuery filters a storefront catalog search.
type SearchType
type SearchType string
SearchType filters catalog search results by resource kind.
const ( SearchTypeApps SearchType = "apps" SearchTypeBooks SearchType = "books" )
type Storefront
type Storefront struct { Attributes StorefrontAttributes `json:"attributes,omitempty"` Href string `json:"href"` ID string `json:"id"` Type string `json:"type"` }
type StorefrontAttributes
type StorefrontAttributes struct { DefaultLanguageTag string `json:"defaultLanguageTag,omitempty"` Name string `json:"name,omitempty"` SupportedLanguageTags []string `json:"supportedLanguageTags,omitempty"` Unknown map[string]json.RawMessage `json:"-"` }
func (*StorefrontAttributes) UnmarshalJSON
func (s *StorefrontAttributes) UnmarshalJSON(data []byte) error
type StorefrontQuery
type StorefrontQuery struct { Extend ScopedValues Include ScopedValues Language string Platform Platform Relate ScopedValues }
StorefrontQuery filters metadata lookup for a single storefront.
type StorefrontsQuery
type StorefrontsQuery struct { Extend ScopedValues IDs []string Include ScopedValues Language string Platform Platform Relate ScopedValues }
StorefrontsQuery filters metadata lookup for specific storefront IDs.
func (StorefrontsQuery) StorefrontQuery
func (q StorefrontsQuery) StorefrontQuery() StorefrontQuery
type StorefrontsResponse
type StorefrontsResponse struct { Data []Storefront `json:"data"` }
type UnauthorizedResponse
type UnauthorizedResponse struct{}
type UserRating
type UserRating struct { Value float64 `json:"value,omitempty"` RatingCount int `json:"ratingCount,omitempty"` ValueCurrentVersion float64 `json:"valueCurrentVersion,omitempty"` RatingCountCurrentVersion int `json:"ratingCountCurrentVersion,omitempty"` }