bdds

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 23, 2025 License: MIT Imports: 9 Imported by: 0

README

EPO BDDS Go Client

Go Reference

A complete Go client library for the European Patent Office Bulk Data Distribution Service (BDDS).

Getting Started

Authentication

According to EPO, authentication via their CIAM system is mandatory for accessing the Bulk Data Distribution Service. However, in practice:

  • Product/Delivery Listing: Requires authentication (subscription needed)
  • File Downloads: May work without authentication (observed in testing)

For EPO BDDS subscription and official information:

This library supports both authenticated and unauthenticated usage. Provide credentials for full API access, or omit them for download-only usage (where supported).

Installation

go get github.com/patent-dev/epo-bdds

Quick Start

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/patent-dev/epo-bdds"
)

func main() {
    // Create client
    client, err := bdds.NewClient(&bdds.Config{
        Username: "your-epo-username",
        Password: "your-epo-password",
    })
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()

    // List all products
    products, err := client.ListProducts(ctx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d products\n", len(products))
    for _, p := range products {
        fmt.Printf("- [%d] %s\n", p.ID, p.Name)
    }
}

API Methods

Product Discovery
// List all available products
ListProducts(ctx context.Context) ([]*Product, error)

// Get product details with deliveries
GetProduct(ctx context.Context, productID int) (*ProductWithDeliveries, error)

// Find product by name
GetProductByName(ctx context.Context, name string) (*Product, error)

// Get most recent delivery for a product
GetLatestDelivery(ctx context.Context, productID int) (*Delivery, error)
File Downloads
// Download file to writer
DownloadFile(ctx context.Context, productID, deliveryID, fileID int, dst io.Writer) error

// Download with progress callback
DownloadFileWithProgress(ctx context.Context, productID, deliveryID, fileID int,
    dst io.Writer, progressFn func(bytesWritten, totalBytes int64)) error

Configuration

config := &bdds.Config{
    Username:   "your-username",          // Required
    Password:   "your-password",          // Required
    BaseURL:    "https://publication-bdds.apps.epo.org", // Default
    UserAgent:  "YourApp/1.0",           // Optional
    MaxRetries: 3,                        // Default: 3
    RetryDelay: 1,                        // Seconds between retries, default: 1
    Timeout:    30,                       // Request timeout in seconds, default: 30
}

client, err := bdds.NewClient(config)

Features

Automatic Token Management
  • OAuth2 authentication handled automatically
  • Tokens cached and refreshed before expiry
  • No manual token management required
Robust Error Handling
  • Automatic retry with exponential backoff
  • Graceful handling of rate limits
  • Custom error types for different scenarios
Progress Tracking
  • Download progress callbacks for large files
  • Real-time byte tracking during downloads

Usage Examples

Download Without Authentication

If you only need to download files and already have the product/delivery/file IDs:

// Create client without credentials
client, err := bdds.NewClient(&bdds.Config{})
if err != nil {
    log.Fatal(err)
}

// Download file directly
file, err := os.Create("download.zip")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

err = client.DownloadFile(ctx, productID, deliveryID, fileID, file)
if err != nil {
    log.Fatal(err)
}
List Products
products, err := client.ListProducts(ctx)
if err != nil {
    log.Fatal(err)
}

for _, p := range products {
    fmt.Printf("Product %d: %s\n", p.ID, p.Name)
    fmt.Printf("  %s\n", p.Description)
}
Get Product with Deliveries
product, err := client.GetProduct(ctx, 3) // EP DocDB front file
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Product: %s\n", product.Name)
fmt.Printf("Deliveries: %d\n", len(product.Deliveries))

for _, delivery := range product.Deliveries {
    fmt.Printf("  %s - %d files\n", delivery.DeliveryName, len(delivery.Files))
}
Download File with Progress
file, err := os.Create("download.zip")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

err = client.DownloadFileWithProgress(ctx, 3, 12345, 67890, file,
    func(bytesWritten, totalBytes int64) {
        percent := float64(bytesWritten) * 100 / float64(totalBytes)
        fmt.Printf("\rProgress: %.1f%%", percent)
    })
if err != nil {
    log.Fatal(err)
}
Find Product by Name
product, err := client.GetProductByName(ctx, "EP DocDB front file")
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Found product: %d - %s\n", product.ID, product.Name)
Get Latest Delivery
delivery, err := client.GetLatestDelivery(ctx, 3)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Latest delivery: %s\n", delivery.DeliveryName)
fmt.Printf("Published: %s\n", delivery.DeliveryPublicationDatetime)
fmt.Printf("Files: %d\n", len(delivery.Files))

Common Product IDs

ID Name Description
3 EP DocDB front file Bibliographic data (front file)
4 EP full-text data - front file Full-text patent data
14 EP DocDB back file Bibliographic data (back file)
17 PATSTAT Global Patent statistics database
18 PATSTAT EP Register EP register data

Error Handling

The library provides custom error types for different scenarios:

// Authentication errors
if authErr, ok := err.(*bdds.AuthError); ok {
    fmt.Printf("Auth failed: %s\n", authErr.Message)
}

// Not found errors
if notFoundErr, ok := err.(*bdds.NotFoundError); ok {
    fmt.Printf("Resource not found: %s\n", notFoundErr.ID)
}

// Rate limit errors
if rateLimitErr, ok := err.(*bdds.RateLimitError); ok {
    fmt.Printf("Rate limited, retry after %d seconds\n", rateLimitErr.RetryAfter)
}

Testing

This library includes comprehensive test coverage:

Unit Tests (Mock Server)

Offline tests using mock HTTP server with realistic responses:

# Run unit tests
go test -v

# Run with coverage
go test -v -cover

# Generate coverage report
go test -cover -coverprofile=coverage.out
go tool cover -html=coverage.out
Integration Tests (Real API)

Tests that make actual requests to the EPO BDDS API:

# Set credentials
export EPO_BDDS_USERNAME=your-username
export EPO_BDDS_PASSWORD=your-password

# Run integration tests
go test -tags=integration -v

# Run specific test
go test -tags=integration -v -run TestIntegration_ListProducts

Note: Integration tests require valid EPO BDDS credentials and will fail gracefully if not set or if specific products are not accessible (based on account).

Implementation

This library follows a clean architecture:

  1. OpenAPI Specification: Unofficial hand-crafted openapi.yaml based on actual API behavior
  2. Code Generation: Types and client generated using oapi-codegen
  3. Idiomatic Wrapper: Clean Go client wrapping generated code
  4. Automatic Auth: OAuth2 token management handled transparently
Package Structure
├── client.go           # Main client implementation
├── client_test.go     # Unit tests with mock server
├── integration_test.go # Integration tests with real API
├── types.go           # Public types
├── errors.go          # Custom error types
├── utils.go           # Internal utilities
├── generated/         # Auto-generated code
│   ├── types_gen.go   # Generated types
│   └── client_gen.go  # Generated client
└── openapi.yaml      # OpenAPI 3.0 specification

Demo Application

An interactive demo application is included to showcase all library features:

# Set credentials
export EPO_BDDS_USERNAME=your-username
export EPO_BDDS_PASSWORD=your-password

# Run demo
cd demo
go run demo.go

The demo provides an interactive menu for:

  • Listing all products
  • Viewing product details with deliveries
  • Finding products by name
  • Getting latest delivery information
  • Downloading files with progress tracking

See demo/README.md for full documentation.

Development

Regenerating from OpenAPI

If the OpenAPI spec is updated:

# Install generator
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest

# Generate types
oapi-codegen -package generated -generate types openapi.yaml > generated/types_gen.go

# Generate client
oapi-codegen -package generated -generate client openapi.yaml > generated/client_gen.go

Similar Projects

This project follows the style and quality standards of:

License

MIT License - see LICENSE file for details.

Credits

Developed by:

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AuthError

type AuthError struct {
	StatusCode int
	Message    string
}

AuthError represents an authentication error

func (*AuthError) Error

func (e *AuthError) Error() string

type Client

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

Client is the main EPO BDDS API client

func NewClient

func NewClient(config *Config) (*Client, error)

NewClient creates a new EPO BDDS API client Authentication is optional - required only for listing products/deliveries. File downloads work without authentication.

func (*Client) DownloadFile

func (c *Client) DownloadFile(ctx context.Context, productID, deliveryID, fileID int, dst io.Writer) error

DownloadFile downloads a file to the provided writer

func (*Client) DownloadFileWithProgress

func (c *Client) DownloadFileWithProgress(ctx context.Context, productID, deliveryID, fileID int, dst io.Writer, progressFn func(bytesWritten, totalBytes int64)) error

DownloadFileWithProgress downloads a file to the provided writer with progress callback

func (*Client) GetLatestDelivery

func (c *Client) GetLatestDelivery(ctx context.Context, productID int) (*Delivery, error)

GetLatestDelivery returns the most recent delivery for a product

func (*Client) GetProduct

func (c *Client) GetProduct(ctx context.Context, productID int) (*ProductWithDeliveries, error)

GetProduct returns detailed information about a specific product including deliveries

func (*Client) GetProductByName

func (c *Client) GetProductByName(ctx context.Context, name string) (*Product, error)

GetProductByName finds a product by name

func (*Client) ListProducts

func (c *Client) ListProducts(ctx context.Context) ([]*Product, error)

ListProducts returns all available BDDS products

type Config

type Config struct {
	Username   string // EPO BDDS username
	Password   string // EPO BDDS password
	BaseURL    string // Base URL for API (default: https://publication-bdds.apps.epo.org)
	UserAgent  string // Optional custom user agent
	MaxRetries int    // Maximum number of retries (default: 3)
	RetryDelay int    // Seconds between retries (default: 1)
	Timeout    int    // Request timeout in seconds (default: 30)
}

Config holds client configuration

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns default configuration

type Delivery

type Delivery struct {
	DeliveryID                  int
	DeliveryName                string
	DeliveryPublicationDatetime time.Time
	DeliveryExpiryDatetime      *time.Time
	Files                       []*DeliveryFile
}

Delivery represents a product delivery

type DeliveryFile

type DeliveryFile struct {
	FileID                  int
	FileName                string
	FileSize                string
	FileChecksum            string
	FilePublicationDatetime time.Time
}

DeliveryFile represents a file in a delivery

type NotFoundError

type NotFoundError struct {
	Resource string
	ID       string
}

NotFoundError represents a resource not found error

func (*NotFoundError) Error

func (e *NotFoundError) Error() string

type Product

type Product struct {
	ID          int
	Name        string
	Description string
}

Product represents a BDDS product

type ProductWithDeliveries

type ProductWithDeliveries struct {
	ID          int
	Name        string
	Description string
	Deliveries  []*Delivery
}

ProductWithDeliveries represents a product with its deliveries

type RateLimitError

type RateLimitError struct {
	RetryAfter int // seconds
}

RateLimitError represents a rate limit error

func (*RateLimitError) Error

func (e *RateLimitError) Error() string

Directories

Path Synopsis
Package generated provides primitives to interact with the openapi HTTP API.
Package generated 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