Documentation
¶
Overview ¶
Package dkapi provides shared primitives for Google Developer Knowledge API clients.
This module complements (rather than replaces) the official generated client at google.golang.org/api/developerknowledge/v1. It focuses on auth-mode selection, quota-project handling for local ADC, rate-limit retry, AnswerQuery, document retrieval with view selection, batch bisection helpers, and document-name normalization used by dkcli, gcp-docs-mirror-tools, and spanner-mycli.
Authentication supports API keys (DEVELOPERKNOWLEDGE_API_KEY or GOOGLE_API_KEY) and Application Default Credentials. When CLOUDSDK_CONFIG is set, its ADC file provides both token and quota-project metadata when present. If that optional file is absent, standard ADC discovery continues; other path or read errors are returned.
Partial batch retrieval ¶
BatchGetDocumentsPartial chunks large input lists and bisects document-specific failures while preserving input order and duplicate names. WithDocumentView can request metadata-only results. A fatal batch-level error stops later requests but returns the positional results completed before it.
Document views ¶
GetDocument retrieves one document, and WithDocumentView selects how much of it the API returns. DOCUMENT_VIEW_BASIC omits Content while still reporting ContentLengthBytes and UpdateTime, so size and freshness checks do not have to download full content. The same option applies to BatchGetDocumentsPartial.
Index ¶
- Constants
- func APIKeyFromEnv() string
- func CheckResponse(resp *http.Response) ([]byte, error)
- func DefaultADCCredentialsPath(goos, homeDir, appData string) string
- func DefaultCredentialsPath() string
- func IsBisectableDocumentError(err error) bool
- func NewADCHTTPClient(ctx context.Context, cfg AuthConfig) (*http.Client, error)
- func NewAuthenticatedHTTPClient(ctx context.Context, cfg AuthConfig) (*http.Client, string, error)
- func NormalizeDocName(name string) string
- func ParseRetryAfter(resp *http.Response) time.Duration
- func SleepContext(ctx context.Context, wait time.Duration) error
- type ADCCredentialsMetadata
- type APIError
- type Answer
- type AnswerCitation
- type AnswerQueryRequest
- type AnswerQueryResponse
- type AnswerReference
- type AuthConfig
- type AuthMode
- type BatchGetDocumentResult
- type BatchGetOption
- type BatchGetResponse
- type CitationSource
- type Client
- func (c *Client) AnswerQuery(ctx context.Context, req *AnswerQueryRequest) (*AnswerQueryResponse, error)
- func (c *Client) BatchGetDocuments(ctx context.Context, names []string) ([]Document, error)
- func (c *Client) BatchGetDocumentsAll(ctx context.Context, names []string) ([]Document, error)
- func (c *Client) BatchGetDocumentsPartial(ctx context.Context, names []string, opts ...DocumentOption) ([]BatchGetDocumentResult, error)
- func (c *Client) DoAPIRequest(ctx context.Context, method, reqURL string, body []byte, contentType string) ([]byte, error)
- func (c *Client) DoGet(ctx context.Context, reqURL string) ([]byte, error)
- func (c *Client) DoJSONPost(ctx context.Context, reqURL string, body []byte) ([]byte, error)
- func (c *Client) GetDocument(ctx context.Context, name string, opts ...DocumentOption) (*Document, error)
- type Document
- type DocumentChunk
- type DocumentOption
- type DocumentReference
- type DocumentView
- type QuotaProjectTransport
- type RateLimitError
- type TokenSourceFunc
- type Waiter
Examples ¶
Constants ¶
const ( CloudPlatformScope = "https://www.googleapis.com/auth/cloud-platform" DefaultV1BaseURL = "https://developerknowledge.googleapis.com/v1" DefaultHTTPTimeout = time.Minute // MaxBatchGetDocuments is the maximum number of document names accepted by // documents:batchGet. The live v1 and v1alpha APIs rejected 21 names as // INVALID_ARGUMENT on 2026-07-18, despite the how-to page stating 100. // Documents are returned in the same order as names. MaxBatchGetDocuments = 20 )
Variables ¶
This section is empty.
Functions ¶
func APIKeyFromEnv ¶
func APIKeyFromEnv() string
func DefaultCredentialsPath ¶
func DefaultCredentialsPath() string
func NewADCHTTPClient ¶
NewADCHTTPClient constructs an OAuth-authenticated HTTP client. Initial requests are restricted to AuthConfig.AllowedOrigin, which defaults to DefaultV1BaseURL, and redirects must remain on that origin.
func NewAuthenticatedHTTPClient ¶
NewAuthenticatedHTTPClient prefers an environment API key unless ADC is required. Initial requests are restricted to AuthConfig.AllowedOrigin, which defaults to DefaultV1BaseURL, and redirects must remain on that origin.
func NormalizeDocName ¶
NormalizeDocName converts a pasted URL or short document path into a Developer Knowledge API resource name (documents/...). Query strings, fragments, and trailing slashes are stripped. URL-like inputs must be hierarchical ASCII HTTP(S) URLs without userinfo; empty or invalid inputs return "".
Types ¶
type ADCCredentialsMetadata ¶
type ADCCredentialsMetadata struct {
Type string `json:"type"`
QuotaProjectID string `json:"quota_project_id"`
}
func LoadADCCredentialsMetadata ¶
func LoadADCCredentialsMetadata(credentialsPath func() string) ADCCredentialsMetadata
func ResolveQuotaProjectID ¶
func ResolveQuotaProjectID(credentialsPath func() string) (string, ADCCredentialsMetadata)
type Answer ¶ added in v0.3.1
type Answer struct {
AnswerText string `json:"answerText" yaml:"answer_text"`
Citations []AnswerCitation `json:"citations,omitempty" yaml:"citations,omitempty"`
References []AnswerReference `json:"references,omitempty" yaml:"references,omitempty"`
}
Answer is a generated answer and its supporting citations and references.
type AnswerCitation ¶ added in v0.3.1
type AnswerCitation struct {
// StartIndex is the inclusive UTF-8 byte offset of the cited segment.
StartIndex int64 `json:"startIndex" yaml:"start_index"`
// EndIndex is the exclusive UTF-8 byte offset of the cited segment.
EndIndex int64 `json:"endIndex" yaml:"end_index"`
// Sources identify entries in Answer.References.
Sources []CitationSource `json:"sources,omitempty" yaml:"sources,omitempty"`
}
AnswerCitation describes a segment of Answer.AnswerText and its sources.
type AnswerQueryRequest ¶ added in v0.3.1
type AnswerQueryRequest struct {
// Query is the question to answer.
Query string `json:"query" yaml:"query"`
}
AnswerQueryRequest is the request body for AnswerQuery.
type AnswerQueryResponse ¶ added in v0.3.1
type AnswerQueryResponse struct {
// Answer is nil if the service omits the answer object.
Answer *Answer `json:"answer,omitempty" yaml:"answer,omitempty"`
}
AnswerQueryResponse is the response from AnswerQuery.
type AnswerReference ¶ added in v0.3.1
type AnswerReference struct {
DocumentReference *DocumentReference `json:"documentReference,omitempty" yaml:"document_reference,omitempty"`
}
AnswerReference represents a source used to generate an answer.
type AuthConfig ¶
type AuthConfig struct {
Mode AuthMode
Timeout time.Duration
// AllowedOrigin is the hierarchical ASCII HTTP(S) origin accepted by
// constructor-created clients. It defaults to DefaultV1BaseURL.
AllowedOrigin string
// TokenSource overrides ADC discovery. When set, CredentialsPath is ignored.
TokenSource TokenSourceFunc
// QuotaProjectID explicitly sets the x-goog-user-project header for ADC
// clients. It takes precedence over GOOGLE_CLOUD_QUOTA_PROJECT and
// credentials-file metadata.
QuotaProjectID string
// CredentialsPath returns an explicit ADC file path. When set, the path is
// evaluated once and must be readable; ADC discovery does not fall back.
CredentialsPath func() string
}
type BatchGetDocumentResult ¶ added in v0.3.1
BatchGetDocumentResult pairs one input occurrence with its outcome. Name is always populated. Document is set for a returned document, and Err is set for a document-specific failure. Both are nil when a fatal error stopped processing or the API omitted the document from a successful response.
type BatchGetOption ¶ added in v0.3.1
type BatchGetOption = DocumentOption
BatchGetOption is an alias of DocumentOption. It is retained because BatchGetDocumentsPartial introduced the option type under this name.
type BatchGetResponse ¶
type BatchGetResponse struct {
Documents []Document `json:"documents" yaml:"documents"`
}
type CitationSource ¶ added in v0.3.1
type CitationSource struct {
ReferenceIndex int64 `json:"referenceIndex" yaml:"reference_index"`
}
CitationSource identifies a supporting entry in Answer.References.
type Client ¶
type Client struct {
BaseURL string
APIKey string
HTTPClient *http.Client
Limiter Waiter
Verbose bool
VerboseWriter io.Writer
// MaxRetries is the number of additional attempts after the first request.
MaxRetries int
}
func (*Client) AnswerQuery ¶ added in v0.3.1
func (c *Client) AnswerQuery(ctx context.Context, req *AnswerQueryRequest) (*AnswerQueryResponse, error)
AnswerQuery answers a natural-language query using Developer Knowledge content. As of google.golang.org/api v0.289.0, the official generated v1 Go client does not expose this GA operation. See issue #1 for the long-term relationship with that client.
Example ¶
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
dkapi "github.com/apstndb/developerknowledge-go"
)
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_, _ = fmt.Fprint(w, `{"answer":{"answerText":"Use documents:batchGet."}}`)
}))
defer server.Close()
client := &dkapi.Client{BaseURL: server.URL + "/v1", HTTPClient: server.Client()}
resp, err := client.AnswerQuery(context.Background(), &dkapi.AnswerQueryRequest{
Query: "How can I fetch multiple documents?",
})
if err != nil {
panic(err)
}
if resp.Answer == nil {
fmt.Println("No answer returned.")
return
}
fmt.Println(resp.Answer.AnswerText)
}
Output: Use documents:batchGet.
func (*Client) BatchGetDocuments ¶
func (*Client) BatchGetDocumentsAll ¶ added in v0.2.0
BatchGetDocumentsAll fetches documents in chunks of MaxBatchGetDocuments while preserving the order of names. Invalid names fail the whole batch for that chunk.
func (*Client) BatchGetDocumentsPartial ¶ added in v0.3.1
func (c *Client) BatchGetDocumentsPartial( ctx context.Context, names []string, opts ...DocumentOption, ) ([]BatchGetDocumentResult, error)
BatchGetDocumentsPartial fetches names in chunks of MaxBatchGetDocuments and bisects document-specific failures. Results preserve input order and duplicates: len(results) equals len(names), and results[i].Name is names[i].
Document-specific errors are stored in the corresponding result and do not make the method return an error. A non-bisectable error stops processing and is returned with all results completed before the failure. If a successful response contains fewer documents than requested, unmatched results remain nil; response documents that match no remaining input occurrence are ignored.
Example ¶
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
dkapi "github.com/apstndb/developerknowledge-go"
)
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
names := r.URL.Query()["names"]
for _, name := range names {
if name == "documents/example.com/missing" {
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte(
`{"error":{"code":404,"status":"NOT_FOUND","message":"missing"}}`,
))
return
}
}
docs := make([]dkapi.Document, 0, len(names))
for _, name := range names {
docs = append(docs, dkapi.Document{
Name: name,
View: string(dkapi.DocumentViewBasic),
ContentLengthBytes: 42,
})
}
_ = json.NewEncoder(w).Encode(dkapi.BatchGetResponse{Documents: docs})
}))
defer server.Close()
client := &dkapi.Client{
BaseURL: server.URL + "/v1",
HTTPClient: server.Client(),
}
results, err := client.BatchGetDocumentsPartial(
context.Background(),
[]string{
"documents/example.com/guide",
"documents/example.com/missing",
},
dkapi.WithDocumentView(dkapi.DocumentViewBasic),
)
if err != nil {
panic(err)
}
for _, result := range results {
switch {
case result.Err != nil:
fmt.Printf("%s: unavailable\n", result.Name)
case result.Document == nil:
fmt.Printf("%s: omitted\n", result.Name)
default:
fmt.Printf("%s: %d bytes\n", result.Name, result.Document.ContentLengthBytes)
}
}
}
Output: documents/example.com/guide: 42 bytes documents/example.com/missing: unavailable
func (*Client) DoAPIRequest ¶
func (c *Client) DoAPIRequest(ctx context.Context, method, reqURL string, body []byte, contentType string) ([]byte, error)
DoAPIRequest sends an authenticated API request. reqURL must be absolute and share an origin with BaseURL; redirects to another origin are rejected.
func (*Client) DoJSONPost ¶
func (*Client) GetDocument ¶ added in v0.3.2
func (c *Client) GetDocument(ctx context.Context, name string, opts ...DocumentOption) (*Document, error)
GetDocument retrieves a single document by resource name, for example "documents/docs.cloud.google.com/storage/docs/creating-buckets". Use NormalizeDocName to convert a pasted URL into that form; a name with a leading slash, a query string, or a fragment is rejected locally.
WithDocumentView requests a metadata-only document. DOCUMENT_VIEW_BASIC omits Content while still reporting ContentLengthBytes, which makes size and freshness checks much cheaper than fetching full content.
Example (MetadataOnly) ¶
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
dkapi "github.com/apstndb/developerknowledge-go"
)
// WithDocumentView must stay usable where the v0.3.1 option type is expected.
var _ dkapi.BatchGetOption = dkapi.WithDocumentView(dkapi.DocumentViewBasic)
// BatchGetDocumentsPartial must retain its v0.3.1 source-level method shape.
var _ func(context.Context, []string, ...dkapi.BatchGetOption) ([]dkapi.BatchGetDocumentResult, error) = (&dkapi.Client{}).BatchGetDocumentsPartial
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// The BASIC view answers without the content field.
_ = json.NewEncoder(w).Encode(dkapi.Document{
Name: "documents/example.com/guide",
URI: "https://example.com/guide",
View: r.URL.Query().Get("view"),
UpdateTime: "2026-07-18T00:00:00Z",
ContentLengthBytes: 31940,
})
}))
defer server.Close()
client := &dkapi.Client{BaseURL: server.URL + "/v1", HTTPClient: server.Client()}
doc, err := client.GetDocument(
context.Background(),
dkapi.NormalizeDocName("https://example.com/guide"),
dkapi.WithDocumentView(dkapi.DocumentViewBasic),
)
if err != nil {
panic(err)
}
fmt.Printf("%s view=%s bytes=%d content=%q\n",
doc.Name, doc.View, doc.ContentLengthBytes, doc.Content)
}
Output: documents/example.com/guide view=DOCUMENT_VIEW_BASIC bytes=31940 content=""
type Document ¶
type Document struct {
Name string `json:"name" yaml:"name"`
URI string `json:"uri" yaml:"uri"`
Content string `json:"content,omitempty" yaml:"content,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
DataSource string `json:"dataSource,omitempty" yaml:"data_source,omitempty"`
Title string `json:"title,omitempty" yaml:"title,omitempty"`
UpdateTime string `json:"updateTime,omitempty" yaml:"update_time,omitempty"`
View string `json:"view,omitempty" yaml:"view,omitempty"`
ContentLengthBytes int64 `json:"contentLengthBytes,omitempty" yaml:"content_length_bytes,omitempty"`
}
type DocumentChunk ¶
type DocumentOption ¶ added in v0.3.2
type DocumentOption func(*documentRequestConfig)
DocumentOption configures a document retrieval request. The same options apply to GetDocument and BatchGetDocumentsPartial.
func WithDocumentView ¶ added in v0.3.1
func WithDocumentView(view DocumentView) DocumentOption
WithDocumentView sets the document view for every request the call makes. Without this option, the server default applies: DOCUMENT_VIEW_CONTENT for GetDocument and batchGet.
type DocumentReference ¶ added in v0.3.1
type DocumentReference struct {
// DocumentChunk contains the source chunk. The API leaves its ID field empty.
DocumentChunk *DocumentChunk `json:"documentChunk,omitempty" yaml:"document_chunk,omitempty"`
}
DocumentReference represents a document source.
type DocumentView ¶ added in v0.3.1
type DocumentView string
DocumentView selects how much of each Document the API returns.
const ( DocumentViewUnspecified DocumentView = "DOCUMENT_VIEW_UNSPECIFIED" DocumentViewBasic DocumentView = "DOCUMENT_VIEW_BASIC" DocumentViewFull DocumentView = "DOCUMENT_VIEW_FULL" DocumentViewContent DocumentView = "DOCUMENT_VIEW_CONTENT" )
type QuotaProjectTransport ¶
type QuotaProjectTransport struct {
Base http.RoundTripper
Project string
}
func (*QuotaProjectTransport) CloseIdleConnections ¶ added in v0.3.0
func (t *QuotaProjectTransport) CloseIdleConnections()
type RateLimitError ¶
func (*RateLimitError) Error ¶
func (e *RateLimitError) Error() string
type TokenSourceFunc ¶
var DefaultTokenSource TokenSourceFunc = func(ctx context.Context, scopes ...string) (oauth2.TokenSource, error) { return google.DefaultTokenSource(ctx, scopes...) }