Skip to content

gtgt/discogs-api-bundle

Repository files navigation

Discogs API Bundle

A Symfony Bundle providing a complete, type-safe API client for Discogs.com v2.0 API with OAuth 1.0a authentication support.

Features

  • ✅ Complete API coverage: Database (artists, releases, labels, masters), User Collections, Wantlists, Marketplace (listings, orders)
  • ✅ Dual authentication: User-Token (simple) and OAuth 1.0a (full flow)
  • ✅ Value-object models with proper types and immutability
  • ✅ Pagination support with iterator interface
  • ✅ Rate limit handling and automatic retry with exponential backoff
  • ✅ Optional PSR-6 caching with per-endpoint TTL
  • ✅ Event dispatching for extensibility (logging, monitoring)
  • ✅ Symfony 8.0+ compatible, follows bundle best practices
  • ✅ Comprehensive error handling with typed exceptions

Installation

composer require tamas-gere/discogs-api-bundle

Register the bundle

For Symfony Flex projects (recommended): the bundle is auto-registered.

For manual registration, add to config/bundles.php:

return [
    // ...
    DiscogsApiBundle\DiscogsApiBundle::class => ['all' => true],
];

Configure

Copy configuration to your project:

cp vendor/tamas-gere/discogs-api-bundle/config/packages/discogs_api.yaml config/packages/discogs_api.yaml

Edit config/packages/discogs_api.yaml:

discogs_api:
    user_agent: 'MyApp/1.0'  # Required - unique identifier for your app

    # Option 1: Personal token (simplest)
    user_token:
        token: '%env(DISCOGS_USER_TOKEN)%'

    # Option 2: OAuth 1.0a (for multi-user apps)
    # oauth1:
    #     consumer_key: '%env(DISCOGS_CONSUMER_KEY)%'
    #     consumer_secret: '%env(DISCOGS_CONSUMER_SECRET)%'

Get your credentials from Discogs Developer Settings.

Set environment variables in .env:

# Option 1 - Simple token
DISCOGS_USER_TOKEN=your_user_token_here

# Option 2 - OAuth app credentials
DISCOGS_CONSUMER_KEY=your_consumer_key
DISCOGS_CONSUMER_SECRET=your_consumer_secret

Usage

Basic: Personal Token

// In controller or service
public function __construct(private DiscogsClient $discogsClient) {}

// Get a release
$release = $this->discogsClient->getRelease(12345);
echo $release->title;

// Search
$results = $this->discogsClient->search('Daft Punk', [
    'type' => 'artist',
    'per_page' => 10,
]);
foreach ($results as $result) {
    echo $result->title;
}

// Get your identity
$user = $this->discogsClient->getIdentity();

// Add to collection
$this->discogsClient->addToCollection('your_username', $releaseId, folderId: 0, rating: 5, notes: 'Want this');

Advanced: OAuth 1.0a Flow

// Step 1: Redirect user to authorization
$authUrl = $this->generateUrl('discogs_api_oauth_request_token');
// Or call OAuthController::requestToken() directly
// User redirected to Discogs, authorizes app

// Step 2: Handle callback at route "discogs_api_oauth_callback"
// Controller receives token and verifier, exchanges for access token
// Store token credentials in database (user_id -> token, secret)

// Step 3: Configure with stored tokens
// In config/services.yaml:
discogs_api:
    oauth1:
        consumer_key: '%env(DISCOGS_CONSUMER_KEY)%'
        consumer_secret: '%env(DISCOGS_CONSUMER_SECRET)%'
        token: '%user.discogs_token%'  # stored per-user token
        token_secret: '%user.discogs_token_secret%'

// Now all API calls act on behalf of that user
$collection = $discogsClient->getCollection($username);

OAuth Controller Routes (optional)

Enable routes in config/routes.yaml:

discogs_api_oauth:
    resource: '@DiscogsApiBundle/Controller/OAuthController.php'
    type: annotation

Routes:

  • GET /oauth/request-token - Get request token & redirect to Discogs
  • GET /oauth/callback - OAuth callback from Discogs
  • GET /oauth/token - Inspect current session's token
  • POST /oauth/logout - Clear OAuth session

Services

Inject any service individually:

use DiscogsApiBundle\Service\ArtistService;

public function __construct(private ArtistService $artistService) {}

$artist = $this->artistService->getArtist(12345);
$releases = $this->artistService->getArtistReleases(12345, ['per_page' => 20]);

Available services:

  • ArtistService - artists, artist releases, search (artists)
  • ReleaseService - releases, ratings, stats
  • MasterService - master releases, versions
  • LabelService - labels, label releases
  • UserService - user identity, user profiles
  • CollectionService - folders, collection CRUD, ratings
  • WantlistService - wantlist CRUD
  • MarketplaceService - listings CRUD, orders, messages
  • InventoryService - inventory listings CRUD
  • OrderService - order management, messages
  • SearchService - full-text search across all types

Pagination

List methods return PaginatedResponse:

$paginated = $discogsClient->getCollection('username');
foreach ($paginated as $item) {
    // Iterate items
}
echo $paginated->count();       // items on current page
echo $paginated->getPage();     // current page
echo $paginated->getPages();    // total pages
if ($paginated->hasNextPage()) {
    $page = $paginated->getNextPage();
}

Error Handling

All API errors throw exceptions:

use DiscogsApiBundle\Exception\{
    DiscogsApiException,
    RateLimitException,
    AuthenticationException,
    NotFoundException,
    ValidationException
};

try {
    $release = $discogsClient->getRelease(999999999);
} catch (NotFoundException $e) {
    // 404 - resource not found
} catch (AuthenticationException $e) {
    // 401/403 - check your token/keys
} catch (RateLimitException $e) {
    // 429 - rate limit exceeded
    $retryAfter = $e->getRetryAfter();
} catch (DiscogsApiException $e) {
    // other API errors
}

Caching (optional)

Enable caching in config:

discogs_api:
    cache:
        enabled: true
        pool: 'cache.app'  # any PSR-6 pool
        ttl:
            artists: 86400   # 24h
            releases: 43200  # 12h

Cache keys are auto-purged on write operations (add/remove collection, create/update listing).

Events (optional)

Subscribe to events for logging/metrics:

use DiscogsApiBundle\Event\{
    RequestBeforeEvent,
    ResponseEvent,
    ErrorEvent,
    RateLimitEvent
};
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class LoggingSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            'discogs_api.request.before' => 'onRequestBefore',
            'discogs_api.request.after' => 'onRequestAfter',
            'discogs_api.error' => 'onError',
            'discogs_api.rate_limit.exceeded' => 'onRateLimit',
        ];
    }

    public function onRequestBefore(RequestBeforeEvent $event): void
    {
        // Log outgoing request
    }

    public function onError(ErrorEvent $event): void
    {
        // Log errors
    }
}

Testing

Unit Tests

vendor/bin/phpunit tests/Unit

Integration Tests (live API)

By default, live tests are skipped. To run:

# Using env var
DISCOGS_TEST_LIVE=1 vendor/bin/phpunit tests/Integration

# Or with --live flag (if using custom test runner)
vendor/bin/phpunit --group live --live

Configuration for live tests in phpunit.xml.dist:

<php>
    <env name="DISCOGS_USER_TOKEN" value="test_token_here"/>
    <env name="DISCOGS_CONSUMER_KEY" value="key"/>
    <env name="DISCOGS_CONSUMER_SECRET" value="secret"/>
</php>

Rate Limits

Discogs enforces rate limits:

  • Unauthenticated: 60 requests/minute
  • Authenticated: 5000 requests/minute

The bundle automatically tracks X-Ratelimit-Remaining and can retry on 429 with retry_on_rate_limit: true. Configure max_retries for resilience.

Contributing

Contributions welcome! Please read CONTRIBUTING.md for details.

License

MIT License. See LICENSE file.

Resources

About

Moderns Discogs.com API Bundle for Symfony

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages