Ir al contenido principal
Laravel, shipping fast.
Capitulo 15 · Una flota, no un monolito

Un servicio propietario por proveedor

Julian Beaujardin

¿Por qué sólo api-license guarda la credencial de Statamic, en lugar de que cada servicio que pueda llegar a necesitar una licencia haga su propia consulta? Porque la alternativa es la proliferación de credenciales, y eso es un coste que se compone en lugar de pagarse una vez.

La regla es simple: cada proveedor externo lo alcanza exactamente un servicio interno, y ese servicio es el único que guarda sus credenciales. Todos los demás que necesiten la capacidad pasan por el propietario.

// app/Enums/Dependency.php
enum Dependency: string
{
    case GitHub = 'github';       // repos + commits (via api-git)
    case Forge = 'forge';         // server provisioning + deploy
    case Stripe = 'stripe';       // billing + subscriptions
    case OpenAI = 'openai';       // AI content + image generation
    case Registrar = 'registrar'; // domain registration + DNS
}

Cada caso es un proveedor, y el comentario de al lado nombra el único servicio al que se le permite saber que ese proveedor existe. api-server no guarda una clave de Statamic propia. Guarda un cliente que habla con api-license, y deja que api-license sea el único sitio de toda la flota que sabe qué aspecto tiene realmente una carga de licencia de Statamic.

// app/Http/Integrations/Cloud/LicenseAPI.php
final class LicenseAPI
{
    use SendsRequests;

    public function __construct(
        protected PendingRequest $request,
    ) {}

    public static function boot(string $apiKey): LicenseAPI
    {
        return new LicenseAPI(
            request: Http::acceptJson()->withToken(
                token: $apiKey,
            )->baseUrl(
                url: Config::string(/* api-license's base URL */),
            )->timeout(
                seconds: 60,
            ),
        );
    }

    public function getLicenses(): array
    {
        // GETs api-license's own listing route
        return (array) $this->send()->json();
    }

    public function addLicense(string $name, string $url): array
    {
        // POSTs api-license's own create route
        return (array) $this->send(payload: [
            'name' => trim($name),
            'domain' => trim($url),
        ])->json();
    }
}

LicenseAPI es la visión que api-server tiene de la capacidad de licencias, y fíjate en lo que no es: no es un segundo driver de Statamic. Es un cliente HTTP normal apuntado a las propias rutas de api-license. api-server nunca importa un SDK de Statamic, nunca almacena un token de Statamic, nunca tiene una opinión sobre cómo estructura Statamic sus errores. Si Statamic cambia su API mañana, cambia exactamente una base de código: el driver de api-license. Todos los demás servicios que necesitaban una licencia siguieron llamando a LicenseAPI::getLicenses() y no se enteraron.

Esta es la misma idea de Manager, Facade y Driver que el capítulo 1 introdujo, aplicada un nivel más arriba. Dentro de api-license, el Manager oculta qué proveedor hay debajo al resto del código de esa aplicación. Entre servicios, la regla del propietario oculta qué proveedor hay debajo a todas las demás aplicaciones. Es una idea aplicada dos veces, a dos radios distintos. No es coincidencia: es lo que pasa cuando un patrón es realmente bueno, que sigue siendo la respuesta correcta según crece el alcance a su alrededor.