This file provides development guidelines and architectural documentation for the IPFS SDK.
# Build all packages
go build -v ./...
# Build specific package
go build -v ./go.lumeweb.com/ipfs-sdk# Run all tests with race detection and coverage
go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
# Run specific package tests
go test -v ./...
# View coverage report
go tool cover -func=coverage.out# Generate OpenAPI client from swagger.yaml
go generate ./internal/client
# Generate Pinning Service client from IPFS pinning service spec
go generate ./internal/pinning
# Generate mocks for interfaces
mockery# Download dependencies
go mod download
# Verify dependencies
go mod verify
# Tidy dependencies
go mod tidyThis is a Go SDK for interacting with IPFS HTTP gateway services. The SDK uses a layered architecture with the main Client serving as the entry point to specialized services.
- Module path:
go.lumeweb.com/ipfs-sdk - Go version: 1.25.0
The Client struct provides access to five specialized services:
- PinningService - Generated client from IPFS Pinning Service API spec for pinning content
- DNSService - Manage DNS zones and records (DNSLink support)
- IPNSService - Inter-Planetary Naming System key management
- WebsitesService - Gateway website deployment
- UploadService - File upload via TUS resumable upload protocol and HTTP POST
The SDK uses OpenAPI specifications to generate HTTP client code:
Main API Client:
- OpenAPI Spec:
swagger.yamldefines all API endpoints - Generated Client:
internal/client/client.gen.gois generated viago tool oapi-codegen - Adapter Interfaces: Each service (DNS, IPNS, Websites) defines its own interface that wraps the generated client
- Mock Generation:
mockerygenerates test mocks from these adapter interfaces
Pinning Service Client:
- OpenAPI Spec:
internal/pinning/swagger.yaml(from official IPFS Pinning Service API) - Generated Client:
internal/pinning/client.gen.gois generated viago tool oapi-codegen - Type Aliases: Types are exposed cleanly via type aliases to avoid import cycles
- Mock Generation:
mockerygenerates test mocks from the PinningService interface
This pattern isolates the generated code, allows for clean API surfaces on each service, and enables dependency injection for testing.
├── sdk.go, auth.go, retry.go, errors.go, options.go # Core SDK infrastructure
├── pinning.go # Pinning service (generated from IPFS pinning service spec)
├── dns.go # DNS service
├── ipns.go # IPNS service
├── websites.go # Websites service
├── upload.go # Upload service (TUS & HTTP POST + UploadFile)
├── fs/
│ ├── bytesfs.go # fs.FS implementation for byte slices
│ ├── singlefilefs.go # fs.FS implementation for file handles
│ ├── doc.go # Package docs
│ └── *_test.go # Tests
├── internal/
│ ├── client/
│ │ ├── client.gen.go # Generated OpenAPI client
│ │ ├── doc.go # go:generate directive
│ │ └── oai-codegen.yaml # Codegen config
│ ├── http/
│ │ └── http.go # Retry utilities (UnrecoverableStatusCodes)
│ ├── pinning/
│ │ ├── client.gen.go # Generated OpenAPI client (IPFS Pinning Service)
│ │ ├── doc.go # go:generate directive
│ │ ├── oai-codegen.yaml # Codegen config
│ │ └── swagger.yaml # IPFS pinning service spec
│ ├── dnsreq/
│ │ └── types.go # DNS types isolated to avoid import cycles
│ └── testutil/
│ └── http.go # HTTP test utilities
├── pkg/upload/
│ ├── doc.go # Package docs
│ ├── car.go # CAR streaming utilities
│ ├── car_blockstore.go # LRU blockstore implementation
│ ├── car_dir_builder.go # Directory tree builder
│ ├── unixfs_generator.go # UnixFS node generation
│ └── internal/
│ ├── io/ # I/O utilities
│ ├── encoding/ # Encoding utilities
│ └── carv1/ # CARv1 format handling
├── mocks/ # Generated mocks (DNSClientWithResponsesInterface, etc.)
├── swagger.yaml # OpenAPI specification
├── .mockery.yaml # Mockery configuration
├── git-town.toml # Git workflow config
└── knope.toml # Release management
The pkg/upload package implements a two-pass CAR generation approach for handling large directory trees:
- Pass 1: Walk filesystem and build summary with metadata (CIDs, sizes, tree structure)
- Pass 2: Generate CARv1 file by regenerating blocks from filesystem on demand
This uses an LRU blockstore (LRUBlockstore) with configurable memory limits (default 100MB), enabling processing of content larger than available RAM.
The UploadService provides two upload approaches:
-
fs.FS-based Uploads (recommended for files and directories)
UploadFromFS()- Accepts anyfs.FSimplementation for CAR generationUploadFile()- Convenience method wrapping file handles inSingleFileFS- Automatically generates CAR files with content addressing
- Examples:
os.DirFS, testing/fstest.MapFS,fs.BytesFS,fs.SingleFileFS
-
io.Reader-based Uploads (for streams)
Upload()- Accepts anyio.Readerwithout CAR generation- Direct streaming for existing data streams
- Simpler when you don't need CAR format validation
- Examples: HTTP responses, network data, in-memory streams
The fs package provides fs.FS implementations for the upload service:
- BytesFS - Wraps a byte slice as a single-file filesystem for uploading bytes
- SingleFileFS - Wraps an open file handle (
*os.File) as a filesystem- Returns the same file handle on each
Open()call - Automatically seeks to position 0 on each open to support CAR generation's two-pass pattern
IsDir()always returnsfalseto prevent incorrect directory wrapping
- Returns the same file handle on each
Both implementations implement fs.FS and fs.File interfaces, making them compatible with UploadFromFS() for automatic CAR generation and upload.
All services use Bearer token authentication passed via Authorization header. The token is set on the main Client and used by internal request editors.
All HTTP requests use configurable retry behavior via internal/http/http.go:
- Default: 3 attempts with exponential backoff
- Unrecoverable status codes (not retried): 400, 401, 403, 404, 405, 409, 422
- Rate limit (429) is always retried
- Configurable via
RetryConfigper service
Services use type aliases to expose generated types from the internal client package, avoiding direct imports in external-facing APIs. This keeps the public API clean while leveraging generated models.
-
Code Generation: Generated files are auto-generated. Do not edit them manually.
internal/client/client.gen.go- rungo generate ./internal/clientafter modifyingswagger.yamlinternal/pinning/client.gen.go- rungo generate ./internal/pinningafter modifyinginternal/pinning/swagger.yaml
-
Mock Generation: Mocks are generated using mockery. Configure interfaces in
.mockery.yaml. -
Import Cycles: The
internal/dnsreqpackage isolates DNS request types to allow mockery to generate mocks without creating import cycles in test files. -
Service Adapters: Each service (DNS, IPNS, Websites) must define its own
*ClientWithResponsesInterfaceand adapter to convert the generatedClientWithResponsesto the service-specific interface. -
IPFS CID Types: The SDK uses
github.com/ipfs/go-cidfor CID operations. Ensure proper CID validation when calling service methods. -
Context Usage: All service methods accept
context.Context. Always use timeout contexts for operations that may block. -
Error Handling: Service methods return standard Go errors. Check for
context.Canceledwhen operations fail with context cancellation. -
Testing: Use the generated mocks in the
mockspackage withtestify/mockassertions. See existing test files for patterns. UseNewPinningServicewithWithPinningHTTPClientfor testing with custom HTTP clients.