Installation Run:
composer require dms/meetup-api-bundle:~1.*
Add to config/bundles.php:
return [
// ...
DMS\Bundle\MeetupApiBundle\DMSMeetupApiBundle::class => ['all' => true],
];
Configure API Key (Key Auth)
Add to config/packages/dms_meetup_api.yaml:
dms_meetup_api:
client:
key: "%env(MEETUP_API_KEY)%"
Set the env var in .env:
MEETUP_API_KEY=your_api_key_here
First Use Case: Fetch Meetup Events Inject the client in a service:
use DMS\Bundle\MeetupApiBundle\Client\MeetupClientInterface;
class MeetupService
{
public function __construct(private MeetupClientInterface $client) {}
public function getUpcomingEvents(string $groupUrlname)
{
return $this->client->get('/find/groups', [
'group_urlname' => $groupUrlname,
'fields' => 'events',
]);
}
}
Service Integration Use dependency injection to access the client in controllers/services:
// src/Service/MeetupEventService.php
class MeetupEventService
{
public function __construct(
private MeetupClientInterface $client,
private MeetupOAuthClientInterface $oauthClient
) {}
}
OAuth Workflow
Configure OAuth in config/packages/dms_meetup_api.yaml:
dms_meetup_api:
client:
consumer_key: "%env(MEETUP_OAUTH_KEY)%"
consumer_secret: "%env(MEETUP_OAUTH_SECRET)%"
token: "%env(MEETUP_OAUTH_TOKEN)%"
token_secret: "%env(MEETUP_OAUTH_TOKEN_SECRET)%"
Use the OAuth client for user-specific requests:
$this->oauthClient->get('/self', []);
Pagination Handling Loop through paginated results:
$offset = 0;
do {
$events = $this->client->get('/events', [
'offset' => $offset,
'order' => 'time',
]);
// Process events...
$offset += 20; // Meetup's default page size
} while (count($events) > 0);
Error Handling Wrap API calls in try-catch:
try {
$response = $this->client->get('/events');
} catch (\DMS\MeetupApiClient\Exception\ApiException $e) {
// Log or handle error (e.g., rate limit, invalid request)
throw new \RuntimeException('Meetup API error: ' . $e->getMessage());
}
API Key vs. OAuth Confusion
/self or /rsvps).401 Unauthorized errors.Rate Limits
$cacheKey = 'meetup_events_' . $groupUrlname;
if (!$events = $cache->get($cacheKey)) {
$events = $this->client->get('/find/groups', ['group_urlname' => $groupUrlname]);
$cache->set($cacheKey, $events, 3600); // Cache for 1 hour
}
Deprecated Endpoints
/find/groups) may change. Check Meetup API docs for updates.fields parameter to limit response size:
$this->client->get('/events', ['fields' => 'id,time,name']);
Environment Variables
config/ violates security best practices. Always use .env:
# config/packages/dms_meetup_api.yaml
dms_meetup_api:
client:
key: "%env(MEETUP_API_KEY)%"
Enable Debug Mode Configure the client to log requests:
dms_meetup_api:
client:
debug: true # Logs requests/responses to Symfony's logger
Inspect Raw Responses Access the underlying HTTP client for debugging:
$response = $this->client->get('/events');
$rawBody = $response->getBody()->getContents();
Common HTTP Errors
400 Bad Request: Validate query parameters (e.g., group_urlname).401 Unauthorized: Check OAuth tokens or API keys.404 Not Found: Verify endpoint URLs (e.g., /find/groups vs. /groups).Custom Clients Extend the base client for domain-specific logic:
class CustomMeetupClient extends \DMS\MeetupApiClient\Client
{
public function getGroupEvents(string $groupUrlname, int $limit = 10)
{
return $this->get('/find/groups', [
'group_urlname' => $groupUrlname,
'fields' => 'events',
'limit' => $limit,
]);
}
}
Register it as a service:
services:
App\Service\CustomMeetupClient:
arguments:
- "%env(MEETUP_API_KEY)%"
tags: ['dms_meetup_api.client']
Event Subscribers Listen to Meetup API events (e.g., rate limits) via Symfony’s event dispatcher:
// src/EventListener/MeetupRateLimitListener.php
class MeetupRateLimitListener
{
public function onRateLimit(\DMS\MeetupApiClient\Event\RateLimitEvent $event)
{
$this->logger->warning('Meetup API rate limit reached. Retrying in 60s...');
sleep(60);
}
}
Testing Mock the client in PHPUnit:
$mockClient = $this->createMock(MeetupClientInterface::class);
$mockClient->method('get')->willReturn(['events' => []]);
$service = new MeetupEventService($mockClient);
How can I help you explore Laravel packages today?