A modern, type-safe Laravel SDK for the BayLinks URL shortening platform
Features • Installation • Usage • API Reference • Contributing
This Laravel package provides an elegant, fluent interface to the BayLinks API - a powerful URL shortening and management platform for modern businesses. Built on top of Saloon PHP, this SDK offers type-safe request/response handling, robust error management, and seamless Laravel integration.
- 🎯 Type-Safe: Full PHP 8.3+ type safety with PHPStan level 4 analysis
- 🚀 Modern Architecture: Built on Saloon PHP for elegant HTTP client abstraction
- 🔒 Secure: Per-request API key authentication with built-in error handling
- 🧪 Well-Tested: Comprehensive test suite with Pest PHP
- 📦 Laravel Native: First-class Laravel integration with service provider and facade
- 🔄 Bulk Operations: Support for bulk URL creation and management
- 📊 Analytics: Track URL visit records and performance metrics
- 🎨 PSR Compliant: Follows PSR-1, PSR-2, and PSR-12 coding standards
- PHP 8.3 or higher
- Laravel 10.x, 11.x, or 12.x
- Composer 2.x
Install the package via Composer:
composer require palpalani/baylinks-laravelPublish the configuration file:
php artisan vendor:publish --tag="baylinks-laravel-config"This creates config/baylinks-laravel.php with the following structure:
return [
'server' => env('BAYLINKS_SERVER'),
'api' => [
'url' => 'api/v1',
'key' => env('BAYLINKS_API_KEY'),
'secret' => env('BAYLINKS_API_SECRET'),
],
];Update your .env file:
BAYLINKS_SERVER=https://baylinks.io
BAYLINKS_API_KEY=your_api_key_here
BAYLINKS_API_SECRET=your_api_secret_hereuse PalPalani\BayLinks\Facades\BayLinks;
$client = BayLinks::client();
$account = $client->accountDetails()->get('your_api_key');use PalPalani\BayLinks\Facades\BayLinks;
$client = BayLinks::client();
$shortUrl = $client->createShortURL()->post('your_api_key', [
'destination' => 'https://example.com/very-long-url',
'domain' => 'custom.domain.com', // optional
]);use PalPalani\BayLinks\Facades\BayLinks;
$client = BayLinks::client();
$bulkUrls = $client->createBulkURL()->post('your_api_key', [
'destination' => [
'https://example.com/page-1',
'https://example.com/page-2',
'https://example.com/page-3',
],
'domain' => 'custom.domain.com', // optional
'planet' => 'jupiter', // optional
'expire' => 0, // optional (0 = never expires)
'tag' => ['campaign' => 'summer-2024'], // optional metadata
]);$client = BayLinks::client();
$response = $client->updateShortURLStatus()->post('your_api_key', [
'url_id' => 'abc123',
'status' => 'inactive',
]);$client = BayLinks::client();
$visitRecords = $client->ShortUrlVisitRecord()->post('your_api_key', [
'url_id' => 'abc123',
'from_date' => '2024-01-01',
'to_date' => '2024-12-31',
]);use PalPalani\BayLinks\Factory;
class UrlShortenerService
{
public function __construct(
private Factory $bayLinks
) {}
public function shortenUrl(string $url, string $apiKey): mixed
{
return $this->bayLinks
->createShortURL()
->post($apiKey, ['destination' => $url]);
}
}use Saloon\Exceptions\Request\FatalRequestException;
use Saloon\Exceptions\Request\RequestException;
try {
$shortUrl = BayLinks::client()
->createShortURL()
->post('your_api_key', [
'destination' => 'https://example.com',
]);
} catch (FatalRequestException $e) {
// Handle fatal errors (network issues, timeouts, etc.)
Log::error('BayLinks fatal error: ' . $e->getMessage());
} catch (RequestException $e) {
// Handle API errors (validation, authentication, etc.)
Log::error('BayLinks API error: ' . $e->getMessage());
// Access response details
$statusCode = $e->getStatus();
$responseBody = $e->getResponse()->body();
}use PalPalani\BayLinks\Facades\BayLinks;
$client = BayLinks::client();
// or
$client = BayLinks::factory();| Method | Description | Parameters |
|---|---|---|
accountDetails()->get($apiKey) |
Retrieve account information | string $apiKey |
| Method | Description | Parameters |
|---|---|---|
createShortURL()->post($apiKey, $data) |
Create a single short URL | string $apiKey, array $data |
createBulkURL()->post($apiKey, $data) |
Create multiple short URLs | string $apiKey, array $data |
updateShortURLStatus()->post($apiKey, $data) |
Update URL status | string $apiKey, array $data |
ShortUrlVisitRecord()->post($apiKey, $data) |
Get visit analytics | string $apiKey, array $data |
[
'destination' => 'https://example.com/page', // required
'domain' => 'custom.domain.com', // optional
][
'destination' => [ // required (array of URLs)
'https://example.com/page-1',
'https://example.com/page-2',
],
'domain' => 'custom.domain.com', // optional
'planet' => 'jupiter', // optional
'expire' => 0, // optional (seconds, 0 = never)
'tag' => ['key' => 'value'], // optional (metadata)
]Run the full test suite with Pest:
composer testRun tests with coverage:
composer test-coverageRun specific test file:
vendor/bin/pest tests/ExampleTest.phpRun tests with filtering:
vendor/bin/pest --filter=CanCreateShortUrlRun PHPStan static analysis:
composer analyseFormat code with Laravel Pint:
composer formatThis package uses Saloon PHP for HTTP client abstraction:
- Factory: Main connector extending
Saloon\Http\Connector - Resources: Group related API endpoints (
AccountResource,CreateShortURLResource) - Requests: Individual API requests extending
Saloon\Http\Request - Responses: Transform API responses to DTOs
- Objects: Immutable data transfer objects
- Create a new Request class in
src/Requests/{Category}/ - Create a corresponding Response class in
src/Responses/{Category}/ - Add a Resource method or create new Resource in
src/Resources/ - Update the Factory with a new resource method if needed
- Write tests in
tests/
See CLAUDE.md for detailed development guidelines.
This package uses GitHub Actions for automated testing and quality checks:
| Workflow | Purpose | Trigger |
|---|---|---|
| Tests | Run Pest tests across PHP 8.3-8.4, Laravel 11-12, Ubuntu/Windows | Push, PR |
| PHPStan | Static analysis at level 4 | Push, PR |
| Code Coverage | Track test coverage with Codecov | Push, PR |
| Security Scan | Composer audit, dependency review, SBOM generation | Push, PR, Weekly |
| Code Style | Auto-fix with Laravel Pint | Push (branches only) |
| PR Quality | Validate composer.json, check for debug statements | PR only |
All workflows use Composer caching for faster builds and concurrency controls to prevent redundant runs.
Make sure you've published the service provider:
php artisan config:clear
php artisan cache:clear
composer dump-autoloadVerify your API key is correct and active:
// Test connection
try {
$account = BayLinks::client()->accountDetails()->get('your_api_key');
dump($account);
} catch (\Exception $e) {
echo $e->getMessage();
}If you encounter SSL errors in development:
// In config/baylinks-laravel.php (development only!)
// Note: Never disable SSL verification in productionPlease see CHANGELOG for recent changes and version history.
We welcome contributions! Here's how you can help:
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-new-feature - Make your changes and commit:
git commit -am 'Add new feature' - Push to the branch:
git push origin feature/my-new-feature - Submit a pull request
- Follow PSR-1, PSR-2, and PSR-12 coding standards
- Write tests for new features (we use Pest)
- Ensure PHPStan passes at level 4:
composer analyse - Format code with Pint:
composer format - Update documentation for API changes
- Add entries to CHANGELOG.md
# Install dependencies
composer install
# Run tests
composer test
# Run static analysis
composer analyse
# Format code
composer format- Tests pass (
composer test) - Static analysis passes (
composer analyse) - Code is formatted (
composer format) - Documentation is updated
- CHANGELOG.md is updated
If you discover any security-related issues, please email [email protected] instead of using the issue tracker. All security vulnerabilities will be promptly addressed.
- palPalani - Creator & Maintainer
- Prasanth - Core Developer
- All Contributors - Community Contributors
The MIT License (MIT). Please see License File for more information.
Made with ❤️ by palPalani