Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Bullhorn Client Bundle Laravel Package

developersnl/bullhorn-client-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation Run:

    composer require developersnl/bullhorn-client-bundle
    

    For non-Flex projects, manually add the bundle to config/bundles.php.

  2. Configuration Create config/packages/bullhorn_client.yaml with required credentials:

    bullhorn_client:
      authentication:
        clientId: 'your_client_id'
        clientSecret: 'your_client_secret'
        authUrl: 'https://auth-emea.bullhornstaffing.com/oauth/authorize'
        tokenUrl: 'https://auth-emea.bullhornstaffing.com/oauth/token'
        loginUrl: 'https://rest-emea.bullhornstaffing.com/rest-services/login'
      rest:
        username: 'your_username'
        password: 'your_password'
    
  3. First Use Case Inject the client into a service/controller and call an endpoint:

    use Developersnl\BullhornClientBundle\Client\BullhornClient;
    
    class CandidateController extends Controller
    {
        public function __construct(private BullhornClient $client) {}
    
        public function index()
        {
            $candidates = $this->client->get('/candidates');
            return response()->json($candidates);
        }
    }
    

Implementation Patterns

Core Workflows

  1. Authentication Flow The bundle handles OAuth2 token acquisition automatically. Avoid manual token management:

    // No need to manually fetch tokens; the client handles it.
    $this->client->get('/candidates'); // Token is auto-refreshed if expired.
    
  2. CRUD Operations Use standard HTTP methods for REST operations:

    // Create
    $newCandidate = $this->client->post('/candidates', $data);
    
    // Read
    $candidate = $this->client->get('/candidates/123');
    
    // Update
    $this->client->put('/candidates/123', $updatedData);
    
    // Delete
    $this->client->delete('/candidates/123');
    
  3. Query Parameters Pass arrays for filtering/pagination:

    $this->client->get('/candidates', [
        'fields' => ['firstName', 'lastName', 'email'],
        'pageSize' => 50,
        'pageNumber' => 1
    ]);
    
  4. Response Handling Responses are decoded JSON by default. Use getResponse() for raw responses:

    $response = $this->client->get('/candidates');
    $data = $response->getData(); // Decoded JSON
    $status = $response->getStatusCode();
    

Integration Tips

  • Service Layer Pattern Create a dedicated service class to encapsulate Bullhorn logic:

    class BullhornCandidateService
    {
        public function __construct(private BullhornClient $client) {}
    
        public function findByEmail(string $email): ?array
        {
            $candidates = $this->client->get('/candidates', [
                'email' => $email,
                'pageSize' => 1
            ]);
            return $candidates['results'][0] ?? null;
        }
    }
    
  • Event Listeners Extend the client for custom logic (e.g., logging, retries):

    $this->client->on('request', function ($request) {
        logger()->debug('Bullhorn Request:', ['url' => $request->getUri()]);
    });
    
  • Dependency Injection Prefer constructor injection over manual instantiation:

    // ❌ Avoid
    $client = new BullhornClient();
    
    // ✅ Prefer
    public function __construct(private BullhornClient $client) {}
    

Gotchas and Tips

Pitfalls

  1. Token Expiry

    • The bundle auto-refreshes tokens, but ensure your clientSecret and clientId are correct.
    • Debug Tip: Check storage/logs/laravel.log for TokenExpiredException errors.
  2. Endpoint URLs

    • Hardcoded URLs (e.g., rest-emea.bullhornstaffing.com) may not work for US regions. Override in config:
      bullhorn_client:
        authentication:
          authUrl: 'https://auth.bullhornstaffing.com/oauth/authorize' # US region
      
  3. Rate Limiting

    • Bullhorn enforces rate limits (~1000 requests/5 minutes). Cache responses aggressively:
      $candidates = Cache::remember('bullhorn_candidates', now()->addMinutes(5), function () {
          return $this->client->get('/candidates');
      });
      
  4. Field Selection

    • Omitting fields in queries returns all fields, which can bloat responses. Always specify:
      $this->client->get('/candidates', ['fields' => ['id', 'firstName']]);
      

Debugging

  • Enable Verbose Logging Add to config/logging.php:

    'channels' => [
        'bullhorn' => [
            'driver' => 'single',
            'path' => storage_path('logs/bullhorn.log'),
            'level' => 'debug',
        ],
    ],
    

    Then configure the client to use this channel:

    bullhorn_client:
      logging_channel: 'bullhorn'
    
  • Inspect Raw Requests Use a middleware to log requests/responses:

    $this->client->on('request', function ($request) {
        logger()->debug('Request:', [
            'method' => $request->getMethod(),
            'url' => (string) $request->getUri(),
            'body' => $request->getBody()->getContents(),
        ]);
    });
    

Extension Points

  1. Custom Headers Add headers globally via config:

    bullhorn_client:
      headers:
        'X-Custom-Header': 'value'
    

    Or per-request:

    $this->client->get('/candidates', [], [
        'headers' => ['X-Custom-Header' => 'value']
    ]);
    
  2. Response Transformers Extend the Response class to modify decoded data:

    $this->client->on('response', function ($response) {
        $response->setData($this->transformResponse($response->getData()));
    });
    
  3. Mocking for Tests Use the MockHttpClient for unit tests:

    $mockClient = new MockHttpClient();
    $mockClient->shouldReceive('get')->once()->andReturn(['data' => 'mocked']);
    $this->app->instance(BullhornClient::class, $mockClient);
    
  4. Async Operations For long-running tasks, use Laravel Queues:

    dispatch(new SyncBullhornCandidates($this->client));
    
    class SyncBullhornCandidates implements ShouldQueue
    {
        public function handle(BullhornClient $client) {
            $client->get('/candidates'); // Runs asynchronously
        }
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor