resources/boost/skills/saloon/SKILL.md
Saloon-based service layer pattern for all external API integrations. Every new external API integration must use Saloon — no raw HTTP calls.
npx skillsauth add codebar-ag/coding-guidelines saloonInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
app/Services/{ServiceName}/.Http::get() is acceptable.saloonphp/saloon is installed and configured.config/services.php.Http::get(...), file_get_contents, curl)app/Services/{ServiceName}/Saloon\Http\Connector and handles authentication and base URLSaloon\Http\RequestdefaultQuery() for query parametersHasBody + use HasJsonBody trait with defaultBody()Http::get() is acceptable for simple binary file downloads (not API integrations)Services/SKILL.md for naming and class boundariesDirectory Structure:
app/Services/Stripe/
StripeConnector.php
StripeService.php
Requests/
Charges/
CreateChargeRequest.php
ListChargesRequest.php
DataObjects/
ChargeData.php
// Connector
namespace App\Services\Stripe;
use Saloon\Http\Connector;
class StripeConnector extends Connector
{
public function resolveBaseUrl(): string
{
return 'https://api.stripe.com/v1';
}
protected function defaultHeaders(): array
{
return [
'Authorization' => 'Bearer ' . config('services.stripe.secret'),
'Content-Type' => 'application/json',
];
}
}
// GET Request
use Saloon\Enums\Method;
use Saloon\Http\Request;
class ListChargesRequest extends Request
{
protected Method $method = Method::GET;
public function __construct(
protected int $limit = 10,
protected ?string $customer = null,
) {}
public function resolveEndpoint(): string
{
return '/charges';
}
protected function defaultQuery(): array
{
return array_filter([
'limit' => $this->limit,
'customer' => $this->customer,
]);
}
}
// POST Request
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
class CreateChargeRequest extends Request implements HasBody
{
use HasJsonBody;
protected Method $method = Method::POST;
public function __construct(
protected int $amount,
protected string $currency,
protected string $customerId,
) {}
public function resolveEndpoint(): string
{
return '/charges';
}
protected function defaultBody(): array
{
return [
'amount' => $this->amount,
'currency' => $this->currency,
'customer' => $this->customerId,
];
}
}
// Service class
use Saloon\Exceptions\Request\FatalRequestException;
use Saloon\Exceptions\Request\RequestException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
class StripeService
{
public function __construct(?StripeConnector $connector = null)
{
$this->connector = $connector ?? new StripeConnector();
}
/** @return Collection<int, ChargeData> */
public function listCharges(string $customerId): Collection
{
try {
$response = $this->connector->send(
new ListChargesRequest(customer: $customerId)
);
} catch (RequestException|FatalRequestException $exception) {
Log::warning('Stripe request failed.', [
'customer_id' => $customerId,
'message' => $exception->getMessage(),
]);
throw $exception;
}
return collect($response->json('data'))
->map(fn (array $item) => ChargeData::fromArray($item));
}
}
resolveEndpoint(), defaultQuery(), defaultBody()) independently.Http::get(...) or file_get_contents() for API integrationscurl directlyconfig()DTO/SKILL.md — service classes return typed DTOsServices/SKILL.md — general service class conventionstesting
Translation and localization conventions for Laravel. Use when adding user-facing strings, creating translation files, or working with lang/ directory.
tools
Reusable behaviour shared across multiple unrelated classes. Traits provide shared Eloquent scopes, accessors, lifecycle hooks, and small stateless helper methods.
development
Tailwind CSS v4 styling conventions. Use when working with CSS, Tailwind utilities, or customizing the theme in Laravel projects.
development
Orchestration classes that coordinate multiple Actions, external APIs, or domain operations into a cohesive workflow. Services own transaction boundaries and third-party API integrations.