dnscale

package module
v0.0.0-...-64ec21e Latest Latest
Warning

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

Go to latest
Published: Sep 18, 2026 License: MIT Imports: 14 Imported by: 0

README

DNScale Go SDK

Go 1.25+ client for the DNScale API, generated from the public OpenAPI contract bundled as openapi.yaml.

Installation

From your Go module, install the SDK:

go get github.com/dnscaleou/dnscale-go

Quick start

Create an API key in the DNScale dashboard and pass it through Options.APIKey or export it as DNSCALE_API_KEY.

package main

import (
    "context"
    "log"

    dnscale "github.com/dnscaleou/dnscale-go"
)

func main() {
    dns, err := dnscale.New(dnscale.Options{}) // reads DNSCALE_API_KEY
    if err != nil { log.Fatal(err) }
    defer dns.Close()
    ctx := context.Background()

    for zone, err := range dns.Zones.Iter(ctx, 100) {
        if err != nil { log.Fatal(err) }
        for record, err := range dns.Records.Iter(ctx, zone.Id.String(), 100) {
            if err != nil { log.Fatal(err) }
            log.Printf("%s %s %s", zone.Name, record.Name, record.Content)
        }
    }
}

Resources

Zones and Records provide List, Iter, Get, Create, Update, and Delete. Zone IDs are accepted as UUID strings. Record IDs are opaque and content-derived: retain the returned ID after an update.

zone, err := dns.Zones.Create(ctx, dnscale.CreateZoneRequest{Name: "example.com"})
if err != nil { return err }
record, err := dns.Records.Create(ctx, zone.Id.String(), dnscale.CreateRecordRequest{
    Name: "www", Type: "A", Content: "192.0.2.10", Ttl: dnscale.Ptr(300),
})
if err != nil { return err }
err = dns.Records.Delete(ctx, zone.Id.String(), record.Id)

List returns one page. Iter(ctx, pageSize) lazily follows returned counts and has_more, rejects inconsistent/non-progressing pages, and stops making requests when the caller breaks out. Iterators accept page sizes 1–100. Listing is not an atomic snapshot during concurrent writes.

Records.UpdateByName(ctx, zoneID, name, type, body, oldContent) selects an old value when the final pointer is non-nil. Records.DeleteByName(ctx, zoneID, name, type, content) deletes a selected value; nil deletes the entire RRset. An empty content pointer is rejected by the delete helper.

Generated request models use pointers for optional values. dnscale.Ptr(false) and dnscale.Ptr(0) preserve explicit zero values. Nullable fields such as comment use github.com/oapi-codegen/nullable: zero value omits the field, nullable.NewNullNullable[string]() sends null, and nullable.NewNullableWithValue("note") sends a value.

Transport and errors

Options supports APIKey, BaseURL (including /v1), HTTPClient, Timeout, MaxRetries, and RetryBackoff. The default endpoint is https://api.dnscale.eu/v1. The supplied HTTP client is copied, then its timeout and redirect policy are set; its transport and cookie jar are retained.

Only GET/HEAD/OPTIONS without request bodies retry network errors and transient 408/429/500/502/503/504 statuses, up to twice. Mutations are never automatically retried. MaxRetries: dnscale.Ptr(0) disables retries. Retry-After dates and seconds are supported. A delay beyond the 30-second waiting budget surfaces the response instead of retrying too early. Requests have a default total 10-second deadline, including retries; context cancellation interrupts retry waiting. Redirects are not followed. Close() releases idle connections.

Use errors.As for *dnscale.APIError (StatusCode, Code, Message, RequestID, Details) and *dnscale.RateLimitError (also RetryAfter). RateLimitError unwraps to APIError. HTTP metadata survives HTML gateway errors. Transport errors remain standard Go errors. Unexpected success envelopes return *dnscale.ProtocolError.

Full API coverage

dns.API exposes the generated client for all documented operations; models live in github.com/dnscaleou/dnscale-go/api:

result, err := dns.API.GetCurrentUsageWithResponse(ctx)

Both layers use the configured transport and return API errors on unsuccessful HTTP statuses. Directly constructing api.NewClientWithResponses bypasses the SDK's authentication, timeout, retry, and error policy.

Development

GOCACHE="$PWD/.gocache" go test -race ./...
GOCACHE="$PWD/.gocache" go vet ./...
bash scripts/generate.sh

Generation uses pinned oapi-codegen and bundled openapi.yaml. Commit both the contract and generated files. Keep go.mod and go.sum committed.

Live verification creates/deletes a unique disposable zone and requires explicit test credentials with zone/record read/write scopes:

export DNSCALE_TEST_BASE_URL=https://api-sandbox.dnscale.eu/v1
export DNSCALE_TEST_API_KEY=your-disposable-account-key
DNSCALE_LIVE_TEST=1 GOCACHE="$PWD/.gocache" go test -run TestLiveLifecycle -v .

Normal tests skip that lifecycle.

Documentation

Overview

Package dnscale provides a typed client for the DNScale API.

Index

Examples

Constants

View Source
const DefaultBaseURL = "https://api.dnscale.eu/v1"
View Source
const Version = "0.1.0"

Variables

This section is empty.

Functions

func Ptr

func Ptr[T any](value T) *T

Ptr makes an optional request field explicit, including zero and false values.

Types

type APIError

type APIError struct {
	StatusCode int
	Code       string
	Message    string
	RequestID  string
	Details    json.RawMessage
}

APIError retains HTTP and API metadata, even for non-JSON gateway failures.

func (*APIError) Error

func (e *APIError) Error() string

type Client

type Client struct {
	API     *api.ClientWithResponses
	Zones   *ZonesService
	Records *RecordsService
	// contains filtered or unexported fields
}

Client exposes convenient resources and every generated API operation.

func New

func New(options Options) (*Client, error)
Example
package main

import (
	"context"
	"fmt"

	dnscale "github.com/dnscaleou/dnscale-go"
)

func main() {
	client, err := dnscale.New(dnscale.Options{APIKey: "example-key"})
	if err != nil {
		panic(err)
	}
	defer client.Close()
	for zone, err := range client.Zones.Iter(context.Background(), 100) {
		if err != nil {
			panic(err)
		}
		fmt.Println(zone.Name)
	}
}

func (*Client) Close

func (c *Client) Close()

Close releases idle connections. It does not cancel in-flight requests.

type CreateRecordRequest

type CreateRecordRequest = api.CreateRecordRequest
Example
package main

import (
	"fmt"

	dnscale "github.com/dnscaleou/dnscale-go"
	"github.com/oapi-codegen/nullable"
)

func main() {
	request := dnscale.CreateRecordRequest{
		Name: "www", Type: "A", Content: "192.0.2.10", Ttl: dnscale.Ptr(300),
		Comment: nullable.NewNullableWithValue("managed by application"),
	}
	fmt.Println(request.Name)
}
Output:
www

type CreateZoneRequest

type CreateZoneRequest = api.CreateZoneRequest

type Options

type Options struct {
	APIKey     string
	BaseURL    string
	HTTPClient *http.Client
	// Timeout covers one operation including retries; zero defaults to 10 seconds.
	Timeout time.Duration
	// MaxRetries defaults to 2. Use Ptr(0) to disable retries.
	MaxRetries *int
	// RetryBackoff defaults to 250ms. Server Retry-After takes precedence.
	RetryBackoff time.Duration
}

Options configures authentication, transport, and conservative read retries.

type PageOptions

type PageOptions struct {
	Offset int
	Limit  int
}

type ProtocolError

type ProtocolError struct{ Message string }

func (*ProtocolError) Error

func (e *ProtocolError) Error() string

type RateLimitError

type RateLimitError struct {
	*APIError
	RetryAfter string
}

func (*RateLimitError) Unwrap

func (e *RateLimitError) Unwrap() error

type Record

type Record = api.Record

type RecordType

type RecordType = api.RecordType

type RecordsService

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

func (*RecordsService) Create

func (s *RecordsService) Create(ctx context.Context, zoneID string, body CreateRecordRequest) (*Record, error)

func (*RecordsService) Delete

func (s *RecordsService) Delete(ctx context.Context, zoneID, recordID string) error

func (*RecordsService) DeleteByName

func (s *RecordsService) DeleteByName(ctx context.Context, zoneID, name string, kind RecordType, content *string) error

DeleteByName deletes one value when content is non-nil; nil deletes the WHOLE RRset.

func (*RecordsService) Get

func (s *RecordsService) Get(ctx context.Context, zoneID, recordID string) (*Record, error)

func (*RecordsService) Iter

func (s *RecordsService) Iter(ctx context.Context, zoneID string, pageSize int) iter.Seq2[Record, error]

func (*RecordsService) List

func (s *RecordsService) List(ctx context.Context, zoneID string, options PageOptions) (*api.RecordsData, error)

func (*RecordsService) Update

func (s *RecordsService) Update(ctx context.Context, zoneID, recordID string, body CreateRecordRequest) (*Record, error)

func (*RecordsService) UpdateByName

func (s *RecordsService) UpdateByName(ctx context.Context, zoneID, name string, kind RecordType, body UpdateRecordByNameRequest, oldContent *string) (*Record, error)

UpdateByName selects an existing value using oldContent when non-nil.

type UpdateRecordByNameRequest

type UpdateRecordByNameRequest = api.UpdateRecordByNameRequest

type UpdateZoneRequest

type UpdateZoneRequest = api.UpdateZoneRequest

type Zone

type Zone = api.Zone

type ZonesService

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

func (*ZonesService) Create

func (s *ZonesService) Create(ctx context.Context, body CreateZoneRequest) (*Zone, error)

func (*ZonesService) Delete

func (s *ZonesService) Delete(ctx context.Context, zoneID string) error

func (*ZonesService) Get

func (s *ZonesService) Get(ctx context.Context, zoneID string) (*Zone, error)

func (*ZonesService) Iter

func (s *ZonesService) Iter(ctx context.Context, pageSize int) iter.Seq2[Zone, error]

Iter lazily traverses zones. Stop range iteration to avoid further requests. Listing is not an atomic snapshot under concurrent writes.

func (*ZonesService) List

func (s *ZonesService) List(ctx context.Context, options PageOptions) (*api.ZonesData, error)

func (*ZonesService) Update

func (s *ZonesService) Update(ctx context.Context, zoneID string, body UpdateZoneRequest) (*Zone, error)

Directories

Path Synopsis
Package api provides primitives to interact with the openapi HTTP API.
Package api provides primitives to interact with the openapi HTTP API.

Jump to

Keyboard shortcuts

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