Ir al contenido principal
Laravel, shipping fast.

¿Por qué solo la License API tiene la credencial de Statamic, cuando otros servicios a veces necesitan una licencia?

Porque la alternativa es la dispersión de credenciales, y la dispersión se encarece con cada servicio que se suma. A cada proveedor externo llega exactamente un servicio interno, y ese servicio es el único que tiene las credenciales de ese proveedor. Todos los demás que necesitan la capacidad se la piden al dueño.

Así que el hub no tiene un token de Statamic ni una opinión sobre la forma que Statamic les da a sus errores. Tiene un cliente pequeño que llama a los endpoints de licencias de la License API, los mismos endpoints a los que llama cualquier consumidor autorizado. Si Statamic cambia su API mañana, cambia una sola base de código: el driver del Capítulo 3. Todos los demás servicios siguen pidiendo licencias y ni se enteran.

Es el contrato del Capítulo 3 aplicado por segunda vez. Dentro de la License API, LicenseContract le esconde al resto de la aplicación qué proveedor hay debajo. A lo largo del sistema, el servicio dueño se lo esconde a todas las demás aplicaciones.

También te dice qué hacer cuando una hoja parece necesitar a otra. No recibe una segunda credencial ni una línea directa. El hub, que ya ha hablado con las dos, le entrega lo que necesita.

El cliente del otro lado

Este libro ha construido la License API desde dentro. El hub la ve desde fuera, como un consumidor, y el código que usa para llamarla merece el mismo cuidado, porque cada regla que este libro les pidió a los consumidores ahora se te aplica a ti.

Empieza por configurar el cliente una sola vez. El cliente HTTP de Laravel te deja registrar como macro un cliente con nombre y ya configurado:

// app/Providers/AppServiceProvider.php, en boot()
Http::macro('licenses', function (): PendingRequest {
    $config = config('services.licenses');

    return Http::baseUrl($config['url'])
        ->withToken($config['token'])
        ->acceptJson()
        ->connectTimeout(3)
        ->timeout(10)
        ->withHeader('X-Trace-Id', Context::get('trace_id'));
});

Cada llamada a Http::licenses() tiene ahora la URL base, el token, la cabecera Accept, los dos timeouts del Capítulo 3 y el ID de traza del Capítulo 7, de modo que una operación puede seguirse a través de los logs de los dos servicios. Nadie que llame a la License API desde el hub puede olvidar ninguno, porque nadie vuelve a escribirlos. (Documentación de Laravel: HTTP Client › Macros.)

Después envuelve los endpoints en una clase pequeña que hable el lenguaje del hub:

// app/Services/LicenseClient.php
class LicenseClient
{
    public function create(Site $site): string
    {
        // El mismo sitio da la misma clave en cada reintento.
        $key = Uuid::uuid5(
            Uuid::NAMESPACE_URL,
            "webplo:site:{$site->id}",
        )->toString();

        return Http::licenses()
            ->withHeader('Idempotency-Key', $key)
            ->post('/api/licenses', [
                'name' => $site->name,
                'domain' => $site->domain,
            ])
            ->throw()
            ->json('data.key');
    }
}

Tres cosas de ese método son los consejos de este libro vistos desde el otro lado.

La clave de idempotencia se deriva, no es aleatoria. Es un UUID, porque eso es lo que acepta el middleware del Capítulo 8, y un UUID de versión 5 es un hash de un nombre. Construida a partir del ID del sitio, es la misma en cada reintento del job que llama a esto. Es el contrato del Capítulo 8 cumplido desde el lado del cliente, y los nombres estables del Capítulo 10, en una línea.

Lanza una excepción. Una llamada fallida se convierte en una excepción, el job falla, y la política de reintentos de la cola toma el relevo. El cliente no reintenta por su cuenta, por la razón que dio el Capítulo 18: una sola política de reintentos, en un solo lugar.

Devuelve lo que el hub necesita, no lo que envió la API. El hub quiere una clave de licencia. No quiere un array en el que escarbar en cada lugar donde llama. Si la forma de la respuesta de la License API cambia con una versión nueva, este método es la única línea del hub que lo sabe.

Ese último punto es el Resource del Capítulo 2, en espejo. Un Resource decide lo que sale de un servicio. Una clase cliente decide lo que entra en el siguiente. Entre los dos, el JSON que viaja por el cable es un detalle que conocen dos archivos y nada más.

No se pudo cargar el audio. Inténtalo de nuevo en un momento.