Documentation
¶
Overview ¶
Package qdmp is the Go Server SDK for 千岛小程序开放平台 OpenAPI.
Construct a client with NewClient, exchange an app-level access token via Client.Auth.GetAppAccessToken (cached and single-flight refreshed automatically), and call the business operation groups (User, Island, Spu, Tag, Mark, WishSpu, GenAI) on it, passing the caller's credential explicitly on every call as a Context. See the exported types on Client, AuthService, QdmpApiError, and TokenStore for the full contract; the *_test.go files in this directory exercise it end-to-end against mock HTTP servers.
Index ¶
- Variables
- type AppAccessTokenResult
- type AuthService
- func (a *AuthService) GetAppAccessToken(ctx context.Context) (*AppAccessTokenResult, error)
- func (a *AuthService) GetUserAccessToken(ctx context.Context, code string) (*UserAccessTokenResult, error)
- func (a *AuthService) RefreshToken(ctx context.Context, refreshToken string) (*RefreshTokenResult, error)
- type Client
- type ClientOptions
- type Context
- type GenAIDetailResult
- type GenAIGenerateResult
- type GenAIGroup
- type IslandDetailResult
- type IslandGroup
- type IslandInfo
- type MarkAddResult
- type MarkDetailResult
- type MarkGroup
- func (g *MarkGroup) Add(ctx context.Context, qdmpCtx Context, body generated.MarkAddJSONBody) (*MarkAddResult, error)
- func (g *MarkGroup) Detail(ctx context.Context, qdmpCtx Context, params generated.MarkDetailParams) (*MarkDetailResult, error)
- func (g *MarkGroup) List(ctx context.Context, qdmpCtx Context, params generated.MarkListParams) (*MarkListResult, error)
- func (g *MarkGroup) Search(ctx context.Context, qdmpCtx Context, params generated.MarkSearchParams) (*MarkSearchResult, error)
- type MarkHistoryItem
- type MarkItem
- type MarkListResult
- type MarkSearchResult
- type QdmpApiError
- type Rating
- type RefreshTokenResult
- type SpuDetailResult
- type SpuGroup
- type SpuInfo
- type SpuSearchItem
- type SpuSearchResult
- type SpuSummary
- type TagDetailResult
- type TagGroup
- type TagInfo
- type TagSearchResult
- type TokenEntry
- type TokenStore
- type UserAccessTokenResult
- type UserGroup
- type UserMeResult
- type WishAddResult
- type WishCancelResult
- type WishItem
- type WishListResult
- type WishSpuGroup
- func (g *WishSpuGroup) Add(ctx context.Context, qdmpCtx Context, body generated.WishAddJSONBody) (*WishAddResult, error)
- func (g *WishSpuGroup) Cancel(ctx context.Context, qdmpCtx Context, body generated.WishCancelJSONBody) (*WishCancelResult, error)
- func (g *WishSpuGroup) List(ctx context.Context, qdmpCtx Context, params generated.WishListParams) (*WishListResult, error)
Constants ¶
This section is empty.
Variables ¶
var ErrAccessTokenRequired = errors.New("qdmp: access token is required")
ErrAccessTokenRequired is a sentinel error returned when a business method that requires a user/app-level access token (x-qdmp-token-required=true in shared/openapi.yaml) is called without one. Callers should use errors.Is to detect this case. The SDK fails locally, before any HTTP request is sent, whenever this error is returned.
var ErrInvalidAccessToken = errors.New("qdmp: access token contains a character that cannot be safely sent as an HTTP header value")
ErrInvalidAccessToken is a sentinel error returned when a caller-supplied access token contains a byte that cannot be safely sent as an HTTP header value (any byte <= 0x1F, or 0x7F/DEL — including a bare tab, 0x09, which Go's net/http would otherwise transmit as-is instead of rejecting it). The SDK fails locally, before any HTTP request is sent, whenever this error is returned.
Functions ¶
This section is empty.
Types ¶
type AppAccessTokenResult ¶ added in v0.2.0
type AppAccessTokenResult struct {
AccessToken string `json:"accessToken"`
// ExpiresAt is the absolute Unix-seconds expiry timestamp as a string,
// matching the wire shape (see UserAccessTokenResult.ExpiresAt).
ExpiresAt string `json:"expiresAt"`
RefreshToken string `json:"refreshToken"`
OpenID string `json:"openId"`
}
AppAccessTokenResult is the CLIENT_CREDENTIALS ("应用凭证") exchange result.
Real traffic capture confirms this grant type returns the very same data shape as the user-level one — {accessToken, expiresAt, refreshToken, openId} — with a genuinely non-empty refreshToken and an empty openId (an app-level token belongs to no user). All four fields are handed back verbatim so the caller can see the real expiry and decide for itself whether to use the refreshToken; the SDK's own renewal strategy for this credential is unchanged (re-exchange via CLIENT_CREDENTIALS ahead of expiry, never via refreshToken).
Validation is deliberately strict only on accessToken/expiresAt: openId is empty by design here, and refreshToken is passed through as received without being required.
func (AppAccessTokenResult) GoString ¶ added in v0.2.0
func (r AppAccessTokenResult) GoString() string
GoString implements fmt.GoStringer — see UserAccessTokenResult.GoString for why.
func (AppAccessTokenResult) LogValue ¶ added in v0.2.0
func (r AppAccessTokenResult) LogValue() slog.Value
LogValue implements slog.LogValuer — see UserAccessTokenResult.LogValue for why.
func (AppAccessTokenResult) String ¶ added in v0.2.0
func (r AppAccessTokenResult) String() string
String implements fmt.Stringer — see UserAccessTokenResult.String for why.
type AuthService ¶
type AuthService struct {
// contains filtered or unexported fields
}
AuthService implements the qdmp OAuth2-flavored auth endpoints.
GetAppAccessToken manages the app-level (CLIENT_CREDENTIALS) token: cached in TokenStore, refreshed automatically ahead of expiry, with concurrent callers collapsed into a single outbound HTTP exchange (single-flight) to avoid a thundering herd against the real qdmp gateway.
GetUserAccessToken and RefreshToken are one-shot exchanges the SDK never caches — user-level tokens are the calling application's responsibility to persist, since a single server process serves many end users and the SDK has no way to know which user a given call belongs to.
func (*AuthService) GetAppAccessToken ¶ added in v0.2.0
func (a *AuthService) GetAppAccessToken(ctx context.Context) (*AppAccessTokenResult, error)
GetAppAccessToken returns a valid app-level ("应用凭证") credential, using the cached value if it is not within tokenRefreshBufferSeconds of expiry, otherwise exchanging for a new one (collapsing concurrent callers via single-flight).
func (*AuthService) GetUserAccessToken ¶ added in v0.2.0
func (a *AuthService) GetUserAccessToken(ctx context.Context, code string) (*UserAccessTokenResult, error)
GetUserAccessToken performs a one-shot AUTHORIZATION_CODE exchange. Never cached — see the AuthService doc comment.
func (*AuthService) RefreshToken ¶
func (a *AuthService) RefreshToken(ctx context.Context, refreshToken string) (*RefreshTokenResult, error)
RefreshToken performs a one-shot refreshToken exchange. Never cached — see the AuthService doc comment. HTTP 200 does not imply success here: an expired refreshToken comes back as HTTP 200 + code=10008, which doRequest already turns into a *QdmpApiError.
type Client ¶
type Client struct {
// Auth manages the app-level (CLIENT_CREDENTIALS) token lifecycle
// (cached + single-flight refresh) plus the one-shot,
// never-cached getUserAccessToken/refreshToken exchanges.
Auth *AuthService
User *UserGroup
Island *IslandGroup
Spu *SpuGroup
Tag *TagGroup
Mark *MarkGroup
WishSpu *WishSpuGroup
GenAI *GenAIGroup
// contains filtered or unexported fields
}
Client is the root qdmp SDK client. It exposes Auth (app-level token exchange, using appId/appSecret — no user access token needed) plus every business group (User/Island/Spu/...).
Business group methods take the caller's credential as an explicit Context argument on every call — the SDK holds no user credential of its own and never renews one. This mirrors the Node and Java SDKs, where the credential is likewise passed per call (`qdmp.user.me({accessToken})` / `qdmp.user().me(ctx)`), so the three ends behave identically.
func NewClient ¶
func NewClient(opts ClientOptions) (*Client, error)
NewClient constructs a qdmp SDK client from the given options.
type ClientOptions ¶
type ClientOptions struct {
// AppID is the qdmp application ID. Required.
AppID string
// AppSecret is the qdmp application secret, used only for the
// CLIENT_CREDENTIALS/AUTHORIZATION_CODE token exchange. Required. Never
// logged or attached to any error value produced by this SDK.
AppSecret string
// BaseURL overrides the qdmp OpenAPI host. Defaults to the production
// host. Tests point this at an httptest.Server.
BaseURL string
// QdmpVersion overrides the x-echo-qdmp-version header value sent on
// "standard" authScheme requests. Defaults to "1.0".
QdmpVersion string
// HTTPClient overrides the *http.Client used for outbound requests.
// Defaults to a new client with a defaultHTTPTimeout (30s) request
// timeout, so a hung qdmp endpoint can never block a caller forever. Its
// CheckRedirect is always overridden by NewClient (on a shallow copy,
// never mutating the caller's original client) to refuse redirects --
// see the comment in NewClient for why this can't be left configurable.
HTTPClient *http.Client
// TokenStore overrides the app-level access token cache. Defaults to an
// in-process memory store. See TokenStore for why a pluggable store
// exists (multi-instance deployments).
TokenStore TokenStore
}
ClientOptions configures NewClient.
type Context ¶ added in v0.3.0
type Context struct {
// AccessToken is the user-level (or, where explicitly opted into,
// app-level) access token to authenticate this call with.
AccessToken string
}
Context carries the caller's credential for one business call. It is the Go counterpart of the Node SDK's `{accessToken}` context object and the Java SDK's QdmpContext, and is passed explicitly to every business group method:
me, err := client.User.Me(ctx, qdmp.Context{AccessToken: credential.AccessToken})
The SDK stores no user credential and never renews one. When a call fails because the token expired or was revoked, the *QdmpApiError is returned unchanged; obtaining a new token (see AuthService.RefreshToken) and passing it on the next call is the caller's job.
It is a plain struct with no constructor on purpose: like Node, the token is validated when a call actually uses it (see requireAccessToken), not at construction time, so building a Context can never fail.
type GenAIDetailResult ¶
type GenAIDetailResult struct {
ID string `json:"id"`
Status string `json:"status"`
Response map[string]any `json:"response"`
}
GenAIDetailResult is the response of genai.detail.
type GenAIGenerateResult ¶
type GenAIGenerateResult struct {
ID string `json:"id"`
}
GenAIGenerateResult is the response of genai.generate.
type GenAIGroup ¶
type GenAIGroup struct {
// contains filtered or unexported fields
}
GenAIGroup implements the "genai" operation group. Unlike every other group, genai uses its own distinct authScheme ("genai" in shared/generated/route-meta.json): it sends x-openapi-access-token / x-openapi-app-id instead of access-token / x-echo-qdmp-version, and never sends the latter pair (confirmed by the absence of x-echo-qdmp-version in this group's codeExample, per shared/openapi.yaml).
func (*GenAIGroup) Detail ¶
func (g *GenAIGroup) Detail(ctx context.Context, qdmpCtx Context, params generated.GenaiDetailParams) (*GenAIDetailResult, error)
Detail polls the status/result of an async AI generation task by ID.
generated.GenaiDetailParams also carries this scheme's own header fields (XOpenapiAccessToken, XOpenapiAppId); like SpuGroup.Search, this method never reads them back off params — the real values come from the derived per-call Context's access token and the client's own configured AppID.
func (*GenAIGroup) Generate ¶
func (g *GenAIGroup) Generate(ctx context.Context, qdmpCtx Context, body generated.GenaiGenerateJSONBody) (*GenAIGenerateResult, error)
Generate submits an async AI generation task.
type IslandDetailResult ¶
type IslandDetailResult struct {
Island IslandInfo `json:"island"`
}
IslandDetailResult is the response of island.detail.
type IslandGroup ¶
type IslandGroup struct {
// contains filtered or unexported fields
}
IslandGroup implements the "island" operation group.
func (*IslandGroup) Detail ¶
func (g *IslandGroup) Detail(ctx context.Context, qdmpCtx Context, params generated.IslandDetailParams) (*IslandDetailResult, error)
Detail fetches an island's basic info by ID. Confirmed by real testing to also work with an app-level (CLIENT_CREDENTIALS) token; the SDK still requires the caller to explicitly pass some token (there is no silent app-token fallback).
type IslandInfo ¶
type IslandInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Image string `json:"image"`
Joined bool `json:"joined"`
}
IslandInfo is the island/v1/detail data.island shape, also reused as tag/v1/detail's data.tag.island (a Tag's optionally-associated island).
type MarkAddResult ¶
type MarkAddResult struct {
ID string `json:"id"`
}
MarkAddResult is the response of mark.add.
type MarkDetailResult ¶
type MarkDetailResult struct {
ID string `json:"id"`
Spu *SpuSummary `json:"spu"`
MarkAt string `json:"markAt"`
Count string `json:"count"`
Rating *Rating `json:"rating"`
CreatedAt string `json:"createdAt"`
TypeID string `json:"typeId"`
TypeName string `json:"typeName"`
Marks []MarkHistoryItem `json:"marks"`
HasMore bool `json:"hasMore"`
}
MarkDetailResult is the response of mark.detail.
type MarkGroup ¶
type MarkGroup struct {
// contains filtered or unexported fields
}
MarkGroup implements the "marks" operation group.
func (*MarkGroup) Add ¶
func (g *MarkGroup) Add(ctx context.Context, qdmpCtx Context, body generated.MarkAddJSONBody) (*MarkAddResult, error)
Add adds a mark (optionally with a rating) for a given SPU.
func (*MarkGroup) Detail ¶
func (g *MarkGroup) Detail(ctx context.Context, qdmpCtx Context, params generated.MarkDetailParams) (*MarkDetailResult, error)
Detail fetches a single mark's details, including its history.
func (*MarkGroup) List ¶
func (g *MarkGroup) List(ctx context.Context, qdmpCtx Context, params generated.MarkListParams) (*MarkListResult, error)
List fetches the current user's marks, paginated.
func (*MarkGroup) Search ¶
func (g *MarkGroup) Search(ctx context.Context, qdmpCtx Context, params generated.MarkSearchParams) (*MarkSearchResult, error)
Search searches the current user's marks by category.
type MarkHistoryItem ¶
type MarkHistoryItem struct {
ID string `json:"id"`
MarkAt string `json:"markAt"`
CreatedAt string `json:"createdAt"`
}
MarkHistoryItem is one element of mark.detail's data.marks[] history list.
type MarkItem ¶
type MarkItem struct {
ID string `json:"id"`
Spu *SpuSummary `json:"spu"`
MarkAt string `json:"markAt"`
Count string `json:"count"`
Rating *Rating `json:"rating"`
CreatedAt string `json:"createdAt"`
TypeID string `json:"typeId"`
}
MarkItem is one element of mark.list / mark.search's data.items[].
type MarkListResult ¶
type MarkListResult struct {
Items []MarkItem `json:"items"`
TotalCount string `json:"totalCount"`
}
MarkListResult is the response of mark.list.
type MarkSearchResult ¶
type MarkSearchResult struct {
Items []MarkItem `json:"items"`
TotalCount string `json:"totalCount"`
}
MarkSearchResult is the response of mark.search.
type QdmpApiError ¶
type QdmpApiError struct {
// Code is the normalized business error code (e.g. "10005", "13").
Code string
// Message is the human-readable message reported by the server.
Message string
// RequestID is the request tracing ID, when present (only the "normal"
// business envelope {code,message,requestId,data} carries one; the
// gateway-style envelope {code,message,details} does not).
RequestID string
// HTTPStatus is the transport-level HTTP status code of the response
// that carried this business error.
HTTPStatus int
}
QdmpApiError represents a business-level failure reported by the qdmp OpenAPI, as opposed to a transport-level failure (network error, etc).
This repository has confirmed by real traffic capture that HTTP status is not authoritative: a refreshToken that has expired is HTTP 200 with code=10008, while an invalid access-token is a genuine HTTP 401 with code=10005. Callers must inspect Code, not just check for a non-nil error.
Code is intentionally a string (not a closed enum/int): the qdmp API is known to use non-numeric-looking business codes in one envelope shape and small gRPC-style integer codes in the other, and undocumented codes have already been observed in practice (10005, 20000, 13, 2, ...).
func (*QdmpApiError) Error ¶
func (e *QdmpApiError) Error() string
Error implements the error interface. It intentionally only ever interpolates fields already stored on QdmpApiError (Code/Message/ RequestID/HTTPStatus) — accessToken and appSecret are never stored on this type, so they can never leak through this method.
type Rating ¶
type Rating struct {
Value int `json:"value"`
}
Rating is the { value: 1-5 } rating object attached to a mark.
type RefreshTokenResult ¶
type RefreshTokenResult struct {
AccessToken string `json:"accessToken"`
ExpiresAt string `json:"expiresAt"`
}
RefreshTokenResult is the one-shot refreshToken exchange result. Also never cached by the SDK.
func (RefreshTokenResult) GoString ¶ added in v0.1.1
func (r RefreshTokenResult) GoString() string
GoString implements fmt.GoStringer — see UserAccessTokenResult.GoString for why.
func (RefreshTokenResult) LogValue ¶ added in v0.1.1
func (r RefreshTokenResult) LogValue() slog.Value
LogValue implements slog.LogValuer — see UserAccessTokenResult.LogValue for why.
func (RefreshTokenResult) String ¶ added in v0.1.1
func (r RefreshTokenResult) String() string
String implements fmt.Stringer — see UserAccessTokenResult.String for why.
type SpuDetailResult ¶
type SpuDetailResult struct {
Spu SpuInfo `json:"spu"`
}
SpuDetailResult is the response of spu.detail.
type SpuGroup ¶
type SpuGroup struct {
// contains filtered or unexported fields
}
SpuGroup implements the "spu" operation group.
func (*SpuGroup) Detail ¶
func (g *SpuGroup) Detail(ctx context.Context, qdmpCtx Context, params generated.SpuDetailParams) (*SpuDetailResult, error)
Detail fetches a single SPU's details by ID.
func (*SpuGroup) Search ¶
func (g *SpuGroup) Search(ctx context.Context, qdmpCtx Context, params generated.SpuSearchParams) (*SpuSearchResult, error)
Search searches SPUs by keyword/category/IP-tag filters. Confirmed by real testing to also work with an app-level (CLIENT_CREDENTIALS) token.
generated.SpuSearchParams bundles the query fields together with the "standard" authScheme's header fields (AccessToken, XEchoQdmpVersion) because that is what oapi-codegen produced from the shared openapi.yaml spec (header params and query params both land on the operation's Params struct). This method deliberately never reads params.AccessToken or params.XEchoQdmpVersion — the real access-token comes from the derived per-call Context, and the real x-echo-qdmp-version comes from the client's own configured QdmpVersion — so a caller cannot spoof either header by setting those two fields.
type SpuInfo ¶
type SpuInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Image string `json:"image"`
WhiteBgPng string `json:"whiteBgPng"`
TypeID string `json:"typeId"`
TypeName string `json:"typeName"`
WishCount string `json:"wishCount"`
MarkCount string `json:"markCount"`
WishCount3day string `json:"wishCount3day"`
MarkCount3day string `json:"markCount3day"`
EntryProfileItems []map[string]any `json:"entryProfileItems"`
}
SpuInfo is the spu/v1/detail data.spu shape.
type SpuSearchItem ¶
type SpuSearchItem struct {
ID string `json:"id"`
Name string `json:"name"`
Image string `json:"image"`
TypeID string `json:"typeId"`
TypeName string `json:"typeName"`
WishCount string `json:"wishCount"`
MarkCount string `json:"markCount"`
}
SpuSearchItem is one element of spu.search's data.items[].
type SpuSearchResult ¶
type SpuSearchResult struct {
Items []SpuSearchItem `json:"items"`
TotalCount string `json:"totalCount"`
}
SpuSearchResult is the response of spu.search.
type SpuSummary ¶
type SpuSummary struct {
ID string `json:"id"`
Name string `json:"name"`
Image string `json:"image"`
}
SpuSummary is the small SPU summary shape ({id, name, image}) embedded in mark/wishspu list-style responses' data.items[].spu field.
type TagDetailResult ¶
type TagDetailResult struct {
Tag TagInfo `json:"tag"`
}
TagDetailResult is the response of tag.detail.
type TagGroup ¶
type TagGroup struct {
// contains filtered or unexported fields
}
TagGroup implements the "tag" operation group.
func (*TagGroup) Detail ¶
func (g *TagGroup) Detail(ctx context.Context, qdmpCtx Context, params generated.TagDetailParams) (*TagDetailResult, error)
Detail fetches a single Tag's details by ID.
func (*TagGroup) Search ¶
func (g *TagGroup) Search(ctx context.Context, qdmpCtx Context, params generated.TagSearchParams) (*TagSearchResult, error)
Search searches Tags by keyword/category filters.
type TagInfo ¶
type TagInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Image string `json:"image"`
TypeID string `json:"typeId"`
TypeName string `json:"typeName"`
Island *IslandInfo `json:"island"`
}
TagInfo is the tag/v1/detail data.tag shape, also reused by tag/v1/search's data.items[].
type TagSearchResult ¶
type TagSearchResult struct {
Items []TagInfo `json:"items"`
TotalCount string `json:"totalCount"`
}
TagSearchResult is the response of tag.search.
type TokenEntry ¶
TokenEntry is a cached app-level ("应用凭证") credential: the whole thing, not just the access token. ExpiresAt mirrors the wire format confirmed by real traffic capture — an absolute Unix seconds timestamp, not a relative "seconds remaining" duration and not milliseconds — parsed from the string the server sends.
RefreshToken and OpenID are cached alongside so that a call served from this cache returns exactly the same fields as the call that performed the exchange (see AppAccessTokenResult). The CLIENT_CREDENTIALS grant really does return a non-empty refreshToken and an empty openId; neither is required, and neither changes how the SDK renews this credential (it re-exchanges ahead of expiry, it never uses this refreshToken).
type TokenStore ¶
type TokenStore interface {
Get() (TokenEntry, bool)
Set(entry TokenEntry)
Clear()
}
TokenStore is the pluggable persistence interface for the SDK's app-level (CLIENT_CREDENTIALS) token cache. The default implementation is an in-process memory store; multi-instance deployments can supply their own (e.g. backed by Redis) so that all instances share one cached token instead of each independently exchanging one and colliding/rate-limiting each other against the real qdmp gateway.
User-level tokens (from AUTHORIZATION_CODE) are never stored here — the SDK never caches them, per the token lifecycle model in the design.
func NewMemoryTokenStore ¶
func NewMemoryTokenStore() TokenStore
NewMemoryTokenStore returns a TokenStore backed by process memory. This is the default used by NewClient when ClientOptions.TokenStore is nil.
type UserAccessTokenResult ¶ added in v0.2.0
type UserAccessTokenResult struct {
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
// ExpiresAt is the absolute Unix-seconds expiry timestamp, confirmed by
// capture to be a *string* on the wire (e.g. "1785508950") even though
// it is logically an int64. It is intentionally kept as a Go string
// end-to-end so this round-trips byte-for-byte with no risk of a
// numeric-conversion implementation silently corrupting it.
ExpiresAt string `json:"expiresAt"`
OpenID string `json:"openId"`
}
UserAccessTokenResult is the one-shot AUTHORIZATION_CODE exchange result. The SDK never caches this — the caller's own store/DB persists it, scoped to whichever end-user the code belonged to.
func (UserAccessTokenResult) GoString ¶ added in v0.2.0
func (r UserAccessTokenResult) GoString() string
GoString implements fmt.GoStringer. The %#v verb does NOT consult fmt.Stringer — it falls back to Go-syntax struct reflection, which would print every exported field (including the raw AccessToken/RefreshToken) even with String() defined above. GoStringer is the only way to also redact under %#v.
func (UserAccessTokenResult) LogValue ¶ added in v0.2.0
func (r UserAccessTokenResult) LogValue() slog.Value
LogValue implements slog.LogValuer. Structured loggers built on log/slog (e.g. slog.JSONHandler, slog.TextHandler) do NOT consult fmt.Stringer — slog.JSONHandler JSON-marshals values directly, which would still emit the raw AccessToken/RefreshToken fields even with String()/GoString() already redacting the fmt-based paths above. LogValuer is slog's own redaction hook; it has no effect on json.Marshal (persistence stays exactly as before).
func (UserAccessTokenResult) String ¶ added in v0.2.0
func (r UserAccessTokenResult) String() string
String implements fmt.Stringer so that accidental debug-printing (e.g. fmt.Println(result), fmt.Printf("%v"/"%+v", result), or most structured loggers that fall back to %v/%+v) never leaks the raw AccessToken/ RefreshToken values. This is a value-receiver method, so it is also picked up for *UserAccessTokenResult (a pointer's method set includes all value-receiver methods of the pointed-to type).
This must never affect json.Marshal(result): encoding/json only consults the json.Marshaler interface (MarshalJSON), not fmt.Stringer, so callers that persist the real values via JSON — the entire point of GetUserAccessToken/RefreshToken existing — are unaffected. Direct field access (result.AccessToken) is likewise untouched.
type UserGroup ¶
type UserGroup struct {
// contains filtered or unexported fields
}
UserGroup implements the "user" operation group.
type UserMeResult ¶
type UserMeResult struct {
ID string `json:"id"`
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
IdentityTags []map[string]any `json:"identityTags"`
InterestTags []map[string]any `json:"interestTags"`
}
UserMeResult is the response of user.me (data.identityTags/interestTags have no documented internal shape, per shared/openapi.yaml — modeled as open maps, unverified).
type WishAddResult ¶
type WishAddResult struct {
SuccessCount string `json:"successCount"`
}
WishAddResult is the response of wishspu.add.
type WishCancelResult ¶
type WishCancelResult struct {
SuccessCount string `json:"successCount"`
}
WishCancelResult is the response of wishspu.cancel.
type WishItem ¶
type WishItem struct {
ID string `json:"id"`
Spu *SpuSummary `json:"spu"`
TypeID string `json:"typeId"`
MarkAt string `json:"markAt"`
CreatedAt string `json:"createdAt"`
}
WishItem is one element of wishspu.list's data.items[].
type WishListResult ¶
type WishListResult struct {
Items []WishItem `json:"items"`
TotalCount string `json:"totalCount"`
}
WishListResult is the response of wishspu.list.
type WishSpuGroup ¶
type WishSpuGroup struct {
// contains filtered or unexported fields
}
WishSpuGroup implements the "wishspu" operation group.
func (*WishSpuGroup) Add ¶
func (g *WishSpuGroup) Add(ctx context.Context, qdmpCtx Context, body generated.WishAddJSONBody) (*WishAddResult, error)
Add batch-adds "wish" entries.
func (*WishSpuGroup) Cancel ¶
func (g *WishSpuGroup) Cancel(ctx context.Context, qdmpCtx Context, body generated.WishCancelJSONBody) (*WishCancelResult, error)
Cancel batch-cancels "wish" entries.
func (*WishSpuGroup) List ¶
func (g *WishSpuGroup) List(ctx context.Context, qdmpCtx Context, params generated.WishListParams) (*WishListResult, error)
List fetches the current user's "wish" list, paginated.