Weave 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

Shorty Laravel Package

rezzza/shorty

Shorty is a PHP URL shortener library that creates compact links, stores short codes, and resolves redirects. It provides a straightforward API for adding link shortening and management to your applications.

Deep Wiki
Context7

Getting Started

rezzza/shorty ("underwear for your long urls") is a thin abstraction over third-party URL shorteners (Bitly, Google, etc.). It was built in the Symfony ecosystem around 2015, so on Laravel you should treat it as a library you wire up yourself, not a package that drops in cleanly.

1. Install

composer require rezzza/shorty

Before committing, confirm the resolved constraint. The last release was December 2015, so on modern PHP (8.x) Composer may resolve an old tag that fails composer install for platform reasons, or silently pull a Guzzle major that has since been replaced. Check composer show rezzza/shorty and, if necessary, add a "config": { "platform": { "php": "7.4" } } override only in a legacy branch — better to fork.

2. Register the service manually

This predates Laravel 5.5 auto-discovery. Add a binding in a service provider:

// app/Providers/AppServiceProvider.php
public function register(): void
{
    $this->app->singleton(\Rezzza\Shorty\Shorty::class, function ($app) {
        return new \Rezzza\Shorty\Shorty(
            config('services.shorty.provider'),
            config('services.shorty.credentials')
        );
    });
}

(Exact constructor signature varies by tag — read vendor/rezzza/shorty/src first, then bind to what's actually there.)

3. Where to look first

  • vendor/rezzza/shorty/src/ — the provider classes tell you which services still have live APIs.
  • vendor/rezzza/shorty/README.md — the only usage docs; they target Symfony, so translate the service-container wiring into a Laravel binding.
  • Your config: put credentials in config/services.php, not a vendor-published file, so they are env-driven.

4. First use case

Shorten a link in a controller and redirect:

public function share(Post $post)
{
    $short = app(\Rezzza\Shorty\Shorty::class)->shorten(
        route('posts.show', $post)
    );

    return response()->json(['url' => $short]);
}

If your chosen provider's API key is valid, that is the whole loop. Getting to this point is 90% of the work with this package; the shortening call itself is trivial.

Implementation Patterns

Wrap it behind your own interface

Because the package is unmaintained, never let Rezzza\Shorty\* types leak into controllers or models. Define a small contract and one adapter:

interface UrlShortener
{
    public function shorten(string $url): string;
}

final class ShortyUrlShortener implements UrlShortener
{
    public function __construct(private \Rezzza\Shorty\Shorty $shorty) {}

    public function shorten(string $url): string
    {
        return $this->shorty->shorten($url);
    }
}

Bind the interface in your provider. When the package finally breaks (or when your provider's API version is retired), you swap one class, not every call site.

Shorten via a model observer

For content that always needs a share link, generate it on save rather than on every render:

class PostObserver
{
    public function created(Post $post): void
    {
        dispatch(function () use ($post) {
            $post->update([
                'short_url' => app(UrlShortener::class)
                    ->shorten($post->permalink()),
            ]);
        })->afterResponse();
    }
}

Store the result in a short_url column. Shortening is a network call — never do it inside a Blade template or an accessor that runs per row.

Cache aggressively

Short URLs are immutable for a given long URL (within a provider). Cache them:

public function shorten(string $url): string
{
    return Cache::remember(
        'shorty:'.md5($url),
        now()->addMonth(),
        fn () => $this->shorty->shorten($url),
    );
}

This also protects you from rate limits, which is the single most common production failure with these providers.

Batch/queued shortening

Importing a few hundred links? Fan out one job per URL with a rate-limited queue:

public function process(Batch $batch)
{
    foreach ($batch->links as $link) {
        ShortenLink::dispatch($link)->onQueue('shorty');
    }
}

Configure the queue worker with a low throughput and a RateLimited middleware (Illuminate\Queue\Middleware\RateLimited::class) so you respect the provider's per-minute quota instead of burning through it in a second.

Provider strategy and extension point

The library's design is provider-per-class: you configure a provider name and credentials, and the Shorty object delegates. If the bundled provider list is stale (very likely by now), extend it with a small local class implementing the expected interface and register that — for instance a BitlyV4Provider that talks to the current Bitly v4 endpoint. Keep this class in your app, not in a fork of the vendor tree, so composer update doesn't clobber it.

Testing

Do not hit the network in tests. Bind a fake:

$this->app->instance(UrlShortener::class, new class implements UrlShortener {
    public function shorten(string $url): string
    {
        return 'https://sho.rt/'.substr(md5($url), 0, 7);
    }
});

Then assert on the fake's deterministic output. Add a single integration test (marked @group external) that hits the real provider against a known URL to catch credential/API drift.

Gotchas and Tips

It is effectively abandoned — budget for that

Last release December 2015. It predates Laravel auto-discovery, uses older PSR conventions, and pins Guzzle versions that conflict with current Laravel/Symfony HTTP clients. Do a timeboxed spike: install it in a throwaway app and confirm the resolved dependency graph before promising it to anyone. If it fights you for more than a few hours, implementing a 40-line Bitly client yourself is a better investment than a fork.

Provider APIs have moved on

  • Google URL Shortener (goo.gl) was shut down in 2019 — any provider class targeting it is dead code.
  • Bitly moved to v4 with OAuth access tokens; the old login + api_key pair no longer authenticates.
  • Most shorteners now require HTTPS targets and reject arbitrary schemes or localhost/private IPs.

Expect to write your own provider adapter against the current API regardless of what ships in the box.

Config caching bites

If you bind credentials in a closure reading config(), remember php artisan config:cache. In deployments where .env changes without re-caching config, you get a Shorty constructed with null credentials that fails only at the first shorten() call — long after boot. Fail fast: validate credentials in the service provider and throw on missing values.

Error handling and rate limits

The library tends to surface provider errors as generic exceptions. Wrap calls so you can distinguish transient failures (429, 5xx, timeouts) from permanent ones (invalid URL, revoked token):

try {
    $short = $this->shorty->shorten($url);
} catch (\Throwable $e) {
    Log::warning('Shortening failed', ['url' => $url, 'error' => $e->getMessage()]);
    throw $e; // let the queue retry with backoff
}

Set an HTTP timeout (a few seconds) and retry transient failures with exponential backoff via the queue's retryUntil/backoff. Never let a hanging shortening call block a user-facing request.

Validate input before sending

The providers differ on what they accept, but almost all reject non-HTTP(S) schemes. Normalize and validate first:

$url = filter_var($input, FILTER_VALIDATE_URL);
if (! $url || ! Str::startsWith($url, ['http://', 'https://'])) {
    throw new InvalidArgumentException('Unsupported URL');
}

This turns a confusing remote 400 into a clear local error.

Debugging checklist

When shorten() returns nothing useful:

  1. dd(get_class(app(\Rezzza\Shorty\Shorty::class))) — confirm the binding resolved a real instance.
  2. Confirm the provider name string matches exactly what the library expects (it is case-sensitive in some tags).
  3. Verify the credentials by hitting the provider's endpoint with curl directly — this isolates "package bug" from "API key problem."
  4. Inspect the outgoing request with Laravel's HTTP client events or a debug proxy if the library exposes its transport; if not, drop to vendor/ and read.
  5. Check the response body — providers frequently return HTTP 200 with an error envelope.

Prefer a maintained alternative where possible

For a new project, this package is hard to justify. Either:

  • Use a first-party SDK (e.g. Bitly's current PHP examples) wrapped in your UrlShortener interface, or
  • Keep a self-hosted shortener (e.g. Shlink, YOURLS) behind the same interface so you own the data and the SLA.

The UrlShortener abstraction above makes both paths and a future swap cheap, which is really the day-to-day value of looking at this package at all.

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.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment