api

package
v0.16.1 Latest Latest
Warning

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

Go to latest
Published: Nov 25, 2025 License: Apache-2.0 Imports: 13 Imported by: 2

Documentation

Overview

Package api provides the primary client interface for interacting with SPIKE services.

The API type serves as the main entry point for all SPIKE operations, supporting:

  • Secret management (create, read, update, delete, list, and version control)
  • Policy management (create, read, update, delete, and list access control policies)
  • Cryptographic operations (encrypt and decrypt via streaming or JSON modes)
  • Operator functions (recover and restore using Shamir secret sharing)

All operations use mutual TLS authentication with SPIFFE X.509 certificates and communicate exclusively with SPIKE Nexus servers by default.

Example usage:

// Create a new API client
api := api.New()
if api == nil {
    log.Fatal("Failed to initialize SPIKE API")
}
defer api.Close()

// Store a secret
err := api.PutSecret("app/db/password", map[string]string{
    "username": "admin",
    "password": "secret123",
})

// Retrieve a secret
secret, err := api.GetSecret("app/db/password")

// Create an access policy
err = api.CreatePolicy(
    "db-access",
    "spiffe://example.org/app/*",
    "app/db/*",
    []data.PolicyPermission{data.PermissionRead},
)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type API added in v0.6.0

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

API is the SPIKE API.

func New added in v0.1.13

func New() (*API, *sdkErrors.SDKError)

New creates and returns a new instance of API configured with a SPIFFE source.

It automatically discovers and connects to the SPIFFE Workload API endpoint using the default socket path and creates an X.509 source for authentication with a configurable timeout to prevent indefinite blocking on socket issues.

The timeout can be configured using the SPIKE_SPIFFE_SOURCE_TIMEOUT environment variable (default: 30s).

The API client is configured to communicate exclusively with SPIKE Nexus.

Returns:

  • *API: A configured API instance ready for use, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFEFailedToCreateX509Source: if X509Source creation fails
  • ErrSPIFFEUnableToFetchX509Source: if initial SVID fetch fails

Example:

api, err := New()
if err != nil {
    log.Fatalf("Failed to initialize SPIKE API: %v", err)
}
defer api.Close()

func NewWithSource added in v0.1.13

func NewWithSource(source *workloadapi.X509Source) *API

NewWithSource initializes a new API instance with a pre-configured X509Source. This constructor is useful when you already have an X.509 source or need custom source configuration. The API instance will be configured to only communicate with SPIKE Nexus servers.

Parameters:

  • source: A pre-configured X509Source that provides the client's identity certificates and trusted roots for server validation

Returns:

  • *API: A configured API instance using the provided source

Note: The API client created with this function is restricted to communicate only with SPIKE Nexus instances (using predicate.AllowNexus). If you need to connect to different servers, use New() with a custom predicate instead.

Example usage:

	// Use with custom-configured source
	source, err := workloadapi.NewX509Source(ctx,
 	workloadapi.WithClientOptions(...))
	if err != nil {
	    log.Fatal("Failed to create X509Source")
	}
	api := NewWithSource(source)
	defer api.Close()

func (*API) CipherDecrypt added in v0.15.0

func (a *API) CipherDecrypt(
	version byte, nonce, ciphertext []byte, algorithm string,
) ([]byte, *sdkErrors.SDKError)

CipherDecrypt decrypts data with structured parameters.

It sends version, nonce, ciphertext, and algorithm to SPIKE Nexus and returns the decrypted plaintext.

Parameters:

  • version: The cipher version used during encryption
  • nonce: The nonce bytes used during encryption
  • ciphertext: The encrypted data to decrypt
  • algorithm: The encryption algorithm used (e.g., "AES-GCM")

Returns:

  • []byte: The decrypted plaintext if successful, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from httpPost(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

plaintext, err := api.CipherDecrypt(1, nonce, ciphertext, "AES-GCM")

func (*API) CipherDecryptStream added in v0.7.3

func (a *API) CipherDecryptStream(
	reader io.Reader,
) ([]byte, *sdkErrors.SDKError)

CipherDecryptStream decrypts data from a reader using streaming mode.

It sends the reader content as the request body to SPIKE Nexus for decryption. The data is treated as binary (application/octet-stream) as decryption operates on raw encrypted bytes.

Parameters:

  • reader: The encrypted data source to decrypt

Returns:

  • []byte: The decrypted plaintext if successful, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • Errors from streamPost(): if the streaming request fails
  • ErrNetReadingResponseBody: if reading the response fails

Example:

reader := bytes.NewReader(encryptedData)
plaintext, err := api.CipherDecryptStream(reader)

func (*API) CipherEncrypt added in v0.15.0

func (a *API) CipherEncrypt(
	plaintext []byte, algorithm string,
) ([]byte, *sdkErrors.SDKError)

CipherEncrypt encrypts data with structured parameters.

It sends plaintext and algorithm to SPIKE Nexus and returns the encrypted ciphertext bytes.

Parameters:

  • plaintext: The data to encrypt
  • algorithm: The encryption algorithm to use (e.g., "AES-GCM")

Returns:

  • []byte: The encrypted ciphertext if successful, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from httpPost(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

data := []byte("secret message")
encrypted, err := api.CipherEncrypt(data, "AES-GCM")

func (*API) CipherEncryptStream added in v0.7.3

func (a *API) CipherEncryptStream(
	reader io.Reader,
) ([]byte, *sdkErrors.SDKError)

CipherEncryptStream encrypts data from a reader using streaming mode.

It sends the reader content as the request body to SPIKE Nexus for encryption. The data is treated as binary (application/octet-stream) regardless of its original format, as encryption operates on raw bytes.

Parameters:

  • reader: The data source to encrypt

Returns:

  • []byte: The encrypted ciphertext if successful, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • Errors from streamPost(): if the streaming request fails
  • ErrNetReadingResponseBody: if reading the response fails

Example:

reader := strings.NewReader("sensitive data")
encrypted, err := api.CipherEncryptStream(reader)

func (*API) Close added in v0.6.0

func (a *API) Close() *sdkErrors.SDKError

Close releases any resources held by the API instance.

It ensures proper cleanup of the underlying X509Source. This method should be called when the API instance is no longer needed, typically during application shutdown or cleanup.

Returns:

  • *sdkErrors.SDKError: nil if successful or source is nil, ErrSPIFFEFailedToCreateX509Source if closure fails

Example:

api, err := NewAPI(ctx)
if err != nil {
    log.Fatal(err)
}
defer func() {
    if err := api.Close(); err != nil {
        log.Printf("Failed to close API: %v", err)
    }
}()

func (*API) Contribute added in v0.12.0

func (a *API) Contribute(
	keeperShare secretsharing.Share, keeperID string,
) *sdkErrors.SDKError

Contribute sends a secret share contribution to a SPIKE Keeper during the bootstrap process.

It establishes a mutual TLS connection to the specified Keeper and transmits the keeper's share of the secret. The function marshals the share value, validates its length, and sends it securely to the Keeper. After sending, the contribution is zeroed out in memory for security.

Parameters:

  • keeperShare: The secret share to contribute to the Keeper
  • keeperID: The unique identifier of the target Keeper

Returns:

  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • Errors from net.Post(): if the HTTP request fails

Note: The function will fatally crash (via log.FatalErr) if:

  • Marshal failures (ErrDataMarshalFailure)
  • Share length validation fails (ErrCryptoInvalidEncryptionKeyLength)

func (*API) CreatePolicy added in v0.6.0

func (a *API) CreatePolicy(
	name string, SPIFFEIDPattern string, pathPattern string,
	permissions []data.PolicyPermission,
) *sdkErrors.SDKError

CreatePolicy creates a new policy in the system.

It establishes a mutual TLS connection using the X.509 source and sends a policy creation request to SPIKE Nexus.

Parameters:

  • name: The name of the policy to be created
  • SPIFFEIDPattern: The SPIFFE ID pattern that this policy will apply to
  • pathPattern: The path pattern that this policy will match against
  • permissions: A slice of PolicyPermission defining the access rights

Returns:

  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

permissions := []data.PolicyPermission{
    {Action: "read", Resource: "documents/*"},
}
err := api.CreatePolicy(
    "doc-reader",
    "spiffe://example.org/service/*",
    "/api/documents/*",
    permissions,
)
if err != nil {
    log.Printf("Failed to create policy: %v", err)
}

func (*API) DeletePolicy added in v0.6.0

func (a *API) DeletePolicy(id string) *sdkErrors.SDKError

DeletePolicy removes an existing policy from the system using its unique ID.

Parameters:

  • id: The unique identifier of the policy to be deleted

Returns:

  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

err := api.DeletePolicy("policy-123")
if err != nil {
    log.Printf("Failed to delete policy: %v", err)
}

func (*API) DeleteSecret added in v0.6.0

func (a *API) DeleteSecret(path string) *sdkErrors.SDKError

DeleteSecret deletes the entire secret at the given path.

Parameters:

  • path: Path to the secret to delete

Returns:

  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

err := api.DeleteSecret("secret/path")
if err != nil {
    log.Printf("Failed to delete secret: %v", err)
}

func (*API) DeleteSecretVersions added in v0.6.0

func (a *API) DeleteSecretVersions(
	path string, versions []int,
) *sdkErrors.SDKError

DeleteSecretVersions deletes specified versions of a secret at the given path.

Parameters:

  • path: Path to the secret to delete
  • versions: Array of version numbers to delete

Returns:

  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

err := api.DeleteSecretVersions("secret/path", []int{1, 2})
if err != nil {
    log.Printf("Failed to delete secret versions: %v", err)
}

func (*API) GetPolicy added in v0.6.0

func (a *API) GetPolicy(id string) (*data.Policy, *sdkErrors.SDKError)

GetPolicy retrieves a policy from the system using its unique ID.

Parameters:

  • id: The unique identifier of the policy to retrieve

Returns:

  • *data.Policy: The policy if found, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • ErrAPINotFound: if the policy is not found
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

policy, err := api.GetPolicy("policy-123")
if err != nil {
    if err.Is(sdkErrors.ErrAPINotFound) {
        log.Printf("Policy not found")
        return
    }
    log.Printf("Error retrieving policy: %v", err)
    return
}
log.Printf("Found policy: %+v", policy)

func (*API) GetSecret added in v0.6.0

func (a *API) GetSecret(path string) (*data.Secret, *sdkErrors.SDKError)

GetSecret retrieves the latest version of the secret at the given path.

Parameters:

  • path: Path to the secret to retrieve

Returns:

  • *data.Secret: Secret data if found, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • ErrAPINotFound: if the secret is not found
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

secret, err := api.GetSecret("secret/path")
if err != nil {
    if err.Is(sdkErrors.ErrAPINotFound) {
        log.Printf("Secret not found")
        return
    }
    log.Printf("Error retrieving secret: %v", err)
    return
}

func (*API) GetSecretMetadata added in v0.6.0

func (a *API) GetSecretMetadata(
	path string, version int,
) (*data.SecretMetadata, *sdkErrors.SDKError)

GetSecretMetadata retrieves metadata for a specific version of a secret at the given path.

Parameters:

  • path: Path to the secret to retrieve metadata for
  • version: Version number of the secret to retrieve metadata for

Returns:

  • *data.SecretMetadata: Secret metadata if found, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • ErrAPINotFound: if the secret metadata is not found
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

metadata, err := api.GetSecretMetadata("secret/path", 1)
if err != nil {
    if err.Is(sdkErrors.ErrAPINotFound) {
        log.Printf("Metadata not found")
        return
    }
    log.Printf("Error retrieving metadata: %v", err)
    return
}

func (*API) GetSecretVersion added in v0.6.0

func (a *API) GetSecretVersion(
	path string, version int,
) (*data.Secret, *sdkErrors.SDKError)

GetSecretVersion retrieves a specific version of a secret at the given path.

Parameters:

  • path: Path to the secret to retrieve
  • version: Version number of the secret to retrieve

Returns:

  • *data.Secret: Secret data if found, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • ErrAPINotFound: if the secret is not found
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

secret, err := api.GetSecretVersion("secret/path", 1)
if err != nil {
    if err.Is(sdkErrors.ErrAPINotFound) {
        log.Printf("Secret not found")
        return
    }
    log.Printf("Error retrieving secret: %v", err)
    return
}

func (*API) ListPolicies added in v0.6.0

func (a *API) ListPolicies(
	SPIFFEIDPattern, pathPattern string,
) (*[]data.Policy, *sdkErrors.SDKError)

ListPolicies retrieves policies from the system, optionally filtering by SPIFFE ID and path patterns.

Parameters:

  • SPIFFEIDPattern: The SPIFFE ID pattern to filter policies (empty string matches all SPIFFE IDs)
  • pathPattern: The path pattern to filter policies (empty string matches all paths)

Returns:

  • *[]data.Policy: Array of matching policies, empty array if none found, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from net.Post(): if the HTTP request fails (except ErrAPINotFound)
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Note: Returns (&[]data.Policy{}, nil) if no policies are found (ErrAPINotFound)

Example:

result, err := api.ListPolicies("", "")
if err != nil {
    log.Printf("Error listing policies: %v", err)
    return
}
policies := *result
for _, policy := range policies {
    log.Printf("Found policy: %+v", policy)
}

func (*API) ListSecretKeys added in v0.6.0

func (a *API) ListSecretKeys() (*[]string, *sdkErrors.SDKError)

ListSecretKeys retrieves all secret keys.

Returns:

  • *[]string: Array of secret keys if found, empty array if none found, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from net.Post(): if the HTTP request fails (except ErrAPINotFound)
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Note: Returns (&[]string{}, nil) if no secrets are found (ErrAPINotFound)

Example:

keys, err := api.ListSecretKeys()
if err != nil {
    log.Printf("Error listing keys: %v", err)
    return
}
for _, key := range *keys {
    log.Printf("Found key: %s", key)
}

func (*API) PutSecret added in v0.6.0

func (a *API) PutSecret(
	path string, data map[string]string,
) *sdkErrors.SDKError

PutSecret creates or updates a secret at the specified path with the given values.

Parameters:

  • path: Path where the secret should be stored
  • data: Map of key-value pairs representing the secret data

Returns:

  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

err := api.PutSecret("secret/path", map[string]string{"key": "value"})
if err != nil {
    log.Printf("Failed to put secret: %v", err)
}

func (*API) Recover added in v0.6.0

func (a *API) Recover() (map[int]*[32]byte, *sdkErrors.SDKError)

Recover returns recovery partitions for SPIKE Nexus to be used in a break-the-glass recovery operation.

This should be used when the SPIKE Nexus auto-recovery mechanism isn't successful. The returned shards are sensitive and should be securely stored out-of-band in encrypted form.

Returns:

  • map[int]*[32]byte: Map of shard indices to shard byte arrays if successful, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Note: The function will fatally crash (via log.FatalErr) if:

  • SVID acquisition fails
  • SVID is nil
  • Caller is not SPIKE Pilot (security requirement)

Example:

shards, err := api.Recover()
if err != nil {
    log.Fatalf("Failed to recover shards: %v", err)
}

func (*API) Restore added in v0.6.0

func (a *API) Restore(
	index int, shard *[32]byte,
) (*data.RestorationStatus, *sdkErrors.SDKError)

Restore submits a recovery shard to continue the SPIKE Nexus restoration process.

This is used when SPIKE Keepers cannot provide adequate shards and SPIKE Nexus cannot recall its root key. This is a break-the-glass superuser-only operation that a well-architected SPIKE deployment should not need.

Parameters:

  • index: Index of the recovery shard
  • shard: Pointer to a 32-byte array containing the recovery shard

Returns:

  • *data.RestorationStatus: Status containing shards collected, remaining, and restoration state if successful, nil on error
  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Note: The function will fatally crash (via log.FatalErr) if:

  • SVID acquisition fails
  • SVID is nil
  • Caller is not SPIKE Pilot (security requirement)

Example:

status, err := api.Restore(shardIndex, shardPtr)
if err != nil {
    log.Fatalf("Failed to restore shard: %v", err)
}
log.Printf("Shards collected: %d, remaining: %d",
    status.ShardsCollected, status.ShardsRemaining)

func (*API) UndeleteSecret added in v0.6.0

func (a *API) UndeleteSecret(path string, versions []int) *sdkErrors.SDKError

UndeleteSecret restores previously deleted versions of a secret at the specified path.

Parameters:

  • path: Path to the secret to restore
  • versions: Array of version numbers to restore (empty array attempts no restoration)

Returns:

  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • ErrDataMarshalFailure: if request serialization fails
  • Errors from net.Post(): if the HTTP request fails
  • ErrDataUnmarshalFailure: if response parsing fails
  • Error from FromCode(): if the server returns an error

Example:

err := api.UndeleteSecret("secret/path", []int{1, 2})
if err != nil {
    log.Printf("Failed to undelete secret: %v", err)
}

func (*API) Verify added in v0.12.0

func (a *API) Verify(
	randomText string, nonce, cipherText []byte,
) *sdkErrors.SDKError

Verify performs bootstrap verification with SPIKE Nexus by sending encrypted random text and validating that Nexus can decrypt it correctly.

This ensures that the bootstrap process completed successfully and Nexus has the correct master key. The function sends the nonce and ciphertext to Nexus, receives back a hash, and compares it against the expected hash of the original random text. A match confirms successful bootstrap.

Parameters:

  • randomText: The original random text that was encrypted
  • nonce: The nonce used during encryption
  • cipherText: The encrypted random text

Returns:

  • *sdkErrors.SDKError: nil on success, or one of the following errors:
  • ErrSPIFFENilX509Source: if the X509 source is nil
  • Errors from net.Post(): if the HTTP request fails

Note: The function will fatally crash (via log.FatalErr) if:

  • Marshal failures (ErrDataMarshalFailure)
  • Response parsing failures (ErrDataUnmarshalFailure)
  • Hash verification fails (ErrCryptoCipherVerificationFailed)

Directories

Path Synopsis
entity
data
Package data provides data structures for the SPIKE mTLS REST APIs.
Package data provides data structures for the SPIKE mTLS REST APIs.
v1/reqres
Package reqres provides request and response structures for SPIKE mTLS REST API v1.
Package reqres provides request and response structures for SPIKE mTLS REST API v1.
internal
impl/acl
Package acl provides internal implementation for access control list (ACL) policy management.
Package acl provides internal implementation for access control list (ACL) policy management.
impl/cipher
Package cipher provides internal implementation for cryptographic operations including encryption and decryption.
Package cipher provides internal implementation for cryptographic operations including encryption and decryption.
impl/operator
Package operator provides internal implementation for operator-level functions including recovery and restoration operations using Shamir secret sharing.
Package operator provides internal implementation for operator-level functions including recovery and restoration operations using Shamir secret sharing.
impl/secret
Package secret provides internal implementation for secret management operations.
Package secret provides internal implementation for secret management operations.
Package url provides URL construction utilities for SPIKE API endpoints.
Package url provides URL construction utilities for SPIKE API endpoints.

Jump to

Keyboard shortcuts

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