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

Limoncello Laravel Package

neomerx/limoncello

Integration layer between neomerx/json-api and Symfony-based apps, used by Limoncello quick-start projects (Laravel Limoncello Collins and Lumen Limoncello Shot). Provides JSON:API wiring and conventions; see the wiki for setup and usage.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require neomerx/limoncello
    

    Add to config/app.php under providers:

    Neomerx\Limoncello\LimoncelloServiceProvider::class,
    
  2. Basic Configuration: Publish the config file:

    php artisan vendor:publish --provider="Neomerx\Limoncello\LimoncelloServiceProvider"
    

    Configure API endpoints in config/limoncello.php:

    'endpoints' => [
        'default' => [
            'base_uri' => 'https://api.example.com/v1',
            'auth'     => 'basic',
            'username' => env('API_USERNAME'),
            'password' => env('API_PASSWORD'),
        ],
    ],
    
  3. First API Call:

    use Neomerx\Limoncello\Client;
    
    $client = app(Client::class);
    $response = $client->get('users');
    $data = $response->getData();
    

Key Files to Review

  • config/limoncello.php (API endpoints, defaults)
  • app/Providers/LimoncelloServiceProvider.php (custom bindings if needed)
  • vendor/neomerx/limoncello/src/Client.php (core client logic)

Implementation Patterns

Common Workflows

1. Authenticated Requests

// Basic Auth (configured in config)
$client->get('protected/resource');

// Custom Auth (per-request)
$client->withAuth('oauth', [
    'token' => 'your_oauth_token'
])->get('oauth/resource');

2. Request/Response Handling

// GET with query params
$response = $client->get('users', [
    'filter' => ['active' => true],
    'limit'  => 10
]);

// POST with data
$response = $client->post('users', [
    'name'  => 'John Doe',
    'email' => 'john@example.com'
]);

// Parse response
$data = $response->getData();
$status = $response->getStatusCode();

3. Error Handling

try {
    $response = $client->get('users/123');
    $data = $response->getData();
} catch (\Neomerx\Limoncello\Exception\RequestException $e) {
    Log::error('API Error: ' . $e->getMessage());
    // Handle 4xx/5xx responses
}

4. Middleware Integration

Attach middleware to modify requests/responses:

$client->pushMiddleware(function ($request) {
    $request->setHeader('X-Custom-Header', 'value');
});

$client->pushResponseMiddleware(function ($response) {
    if ($response->getStatusCode() === 404) {
        // Custom 404 logic
    }
});

5. Rate Limiting

Use middleware to enforce rate limits:

$client->pushMiddleware(function ($request) {
    static $count = 0;
    if ($count++ >= 10) {
        throw new \RuntimeException('Rate limit exceeded');
    }
});

Integration Tips

Laravel Ecosystem

  • Service Container: Bind custom clients per endpoint:
    $this->app->bind('api.v2', function () {
        return app(Client::class)->setEndpoint('v2');
    });
    
  • HTTP Client Facade: Create a facade for cleaner syntax:
    // app/Facades/Limoncello.php
    public static function get($endpoint, $params = []) {
        return app(Client::class)->get($endpoint, $params);
    }
    
  • Queue Jobs: Offload API calls to queues:
    dispatch(new FetchUsersFromApiJob($client));
    

Testing

  • Mocking: Use Mockery or Laravel's Http mock:
    $mock = Mockery::mock(Client::class);
    $mock->shouldReceive('get')->andReturn($response);
    $this->app->instance(Client::class, $mock);
    

Gotchas and Tips

Pitfalls

  1. Deprecated Package:

    • Last release in 2015—assume no active maintenance. Validate compatibility with Laravel 5.5+ (may require polyfills).
    • Check for breaking changes if upgrading Laravel versions.
  2. No Built-in Retry Logic:

    • Implement exponential backoff manually for transient failures:
      $attempts = 0;
      while ($attempts < 3) {
          try {
              $response = $client->get('resource');
              break;
          } catch (\Exception $e) {
              $attempts++;
              sleep(2 ** $attempts);
          }
      }
      
  3. Limited Middleware Support:

    • Middleware runs in order, but no built-in support for async middleware (e.g., logging to a queue).
  4. No Native JSON:API Support:

    • Assumes raw JSON responses. For JSON:API spec compliance, add a response transformer:
      $client->pushResponseMiddleware(function ($response) {
          $data = $response->getData();
          return collect($data['data'])->map(function ($item) {
              return [
                  'id'    => $item['id'],
                  'type'  => $item['type'],
                  'attrs' => $item['attributes'],
              ];
          });
      });
      
  5. Config Overrides:

    • Per-request config (e.g., auth) overrides global settings but may not persist across chained calls:
      // Risky: Auth may reset if chained
      $client->withAuth('bearer', ['token' => 'abc'])->get('resource')->post('data');
      

Debugging Tips

  1. Enable Guzzle Debugging: Add to config/limoncello.php:

    'debug' => env('APP_DEBUG', false),
    

    Logs requests/responses to storage/logs/limoncello.log.

  2. Inspect Raw Responses:

    $response = $client->get('resource');
    \Log::debug('Raw Response:', [
        'status'  => $response->getStatusCode(),
        'headers' => $response->getHeaders(),
        'body'    => $response->getBody(),
    ]);
    
  3. Validate API Specs: Use tools like Postman or Insomnia to verify endpoints before integrating.


Extension Points

  1. Custom Response Classes: Extend \Neomerx\Limoncello\Response to add domain-specific methods:

    class ApiResponse extends \Neomerx\Limoncello\Response {
        public function getUser() {
            return $this->getData()['user'];
        }
    }
    

    Bind in LimoncelloServiceProvider:

    $this->app->bind(
        \Neomerx\Limoncello\Response::class,
        ApiResponse::class
    );
    
  2. Plugin System: Create a trait for reusable API logic:

    trait ApiClient {
        public function fetchUser($id) {
            return app(Client::class)->get("users/{$id}");
        }
    }
    
  3. Event Dispatching: Trigger events on successful/failed requests:

    $client->pushMiddleware(function ($request) {
        event(new ApiRequestStarted($request));
    });
    
    $client->pushResponseMiddleware(function ($response) {
        if ($response->isSuccessful()) {
            event(new ApiRequestSucceeded($response));
        } else {
            event(new ApiRequestFailed($response));
        }
    });
    

Performance Considerations

  1. Connection Pooling: Reuse the same Client instance for all requests to leverage HTTP connection pooling:

    $client = app(Client::class); // Singleton
    
  2. Caching Responses: Cache frequent, immutable responses:

    $cacheKey = "api_users_{$limit}";
    $data = Cache::remember($cacheKey, now()->addHours(1), function () use ($client, $limit) {
        return $client->get('users', ['limit' => $limit])->getData();
    });
    
  3. Async Requests: Use Laravel Queues for non-critical API calls:

    dispatch(function () use ($client) {
        $client->get('analytics')->then(function ($response) {
            // Process async
        });
    });
    
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.
terminal42/code-quality-tools
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