Login to bookmark this video
Buy Access to Course
09.

Servicio GitHub: Implementación

|

Share this awesome video!

|

Keep on Learning!

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Ahora que tenemos una idea de lo que necesitamos que haga GithubService, vamos a añadir la lógica interna que obtendrá las incidencias del repositorio dino-park utilizando la API de GitHub.

Añade el cliente y haz una petición

Para hacer peticiones HTTP, en tu terminal, instala el Cliente HTTP de Symfony con:

composer require symfony/http-client

Dentro de GithubService, instala un cliente HTTP con$client = HttpClient::create(). Para hacer una petición, llama a $client->request(). Esto necesita 2 cosas. 1ª: qué método HTTP utilizar, como GET o POST. En este caso, debería ser GET. 2ª: la URL, que pegaré. Esto obtendrá todas las "ediciones" del repositorio dino-park a través de la API de GitHub.

30 lines | src/Service/GithubService.php
// ... lines 1 - 5
use Symfony\Component\HttpClient\HttpClient;
class GithubService
{
public function getHealthReport(string $dinosaurName): HealthStatus
{
// ... lines 12 - 13
$client = HttpClient::create();
$response = $client->request(
method: 'GET',
url: 'https://api.github.com/repos/SymfonyCasts/dino-park/issues'
);
// ... lines 20 - 27
}
}

Analiza la respuesta HTTP

Vale, ¿y ahora qué? Volviendo al repositorio dino-park, GitHub devolverá una respuesta JSON que contiene las incidencias que vemos aquí. Cada incidencia tiene un título con el nombre de un dino y, si la incidencia tiene una etiqueta adjunta, también la obtendremos de vuelta. Así que, establece $client->request() en una nueva variable $response. A continuación, foreach()sobre $response->toArray() como $issue. Lo bueno de utilizar el Cliente HTTP de Symfony es que no tenemos que molestarnos en transformar el JSON de GitHub en una matriz - toArray() hace ese trabajo pesado por nosotros. Dentro de este bucle, comprueba si el título de la incidencia contiene el $dinosaurName. Así queif (str_contains($issue['title'], $dinosaurName)) entonces haremos // Do Somethingcon esa incidencia.

30 lines | src/Service/GithubService.php
// ... lines 1 - 5
use Symfony\Component\HttpClient\HttpClient;
class GithubService
{
public function getHealthReport(string $dinosaurName): HealthStatus
{
// ... lines 12 - 13
$client = HttpClient::create();
$response = $client->request(
method: 'GET',
url: 'https://api.github.com/repos/SymfonyCasts/dino-park/issues'
);
foreach ($response->toArray() as $issue) {
if (str_contains($issue['title'], $dinosaurName)) {
}
}
// ... lines 26 - 27
}
}

Llegados a este punto, hemos encontrado la incidencia para nuestro dinosaurio. ¡Guau! Ahora tenemos que hacer un bucle sobre cada etiqueta para ver si encontramos el estado de salud. Para ayudarte, pegaré un método privado: puedes copiarlo del bloque de código de esta página.

49 lines | src/Service/GithubService.php
// ... lines 1 - 4
use App\Enum\HealthStatus;
// ... lines 6 - 7
class GithubService
{
// ... lines 10 - 29
private function getDinoStatusFromLabels(array $labels): HealthStatus
{
$status = null;
foreach ($labels as $label) {
$label = $label['name'];
// We only care about "Status" labels
if (!str_starts_with($label, 'Status:')) {
continue;
}
// Remove the "Status:" and whitespace from the label
$status = trim(substr($label, strlen('Status:')));
}
return HealthStatus::tryFrom($status);
}
}

Esto toma una matriz de etiquetas... y cuando encuentra una que empieza por Status:, devuelve el enum HealthStatus correcto basado en esa etiqueta.

Ahora, en lugar de // Do Something, dice$health = $this->getDinoStatusFromLabels() y pasa las etiquetas con $issue['labels'].

49 lines | src/Service/GithubService.php
// ... lines 1 - 5
use Symfony\Component\HttpClient\HttpClient;
class GithubService
{
public function getHealthReport(string $dinosaurName): HealthStatus
{
// ... lines 12 - 13
$client = HttpClient::create();
$response = $client->request(
method: 'GET',
url: 'https://api.github.com/repos/SymfonyCasts/dino-park/issues'
);
foreach ($response->toArray() as $issue) {
if (str_contains($issue['title'], $dinosaurName)) {
$health = $this->getDinoStatusFromLabels($issue['labels']);
}
}
// ... lines 26 - 27
}
// ... lines 30 - 49

Y ahora podemos devolver $health. Pero... ¿qué pasa si un número no tiene una etiqueta de estado de salud? Hmm... al principio de este método, establece por defecto $healthen HealthStatus::HEALTHY - porque GenLab nunca olvidaría poner una etiquetaSick a un dino que no se encuentra bien.

49 lines | src/Service/GithubService.php
// ... lines 1 - 7
class GithubService
{
public function getHealthReport(string $dinosaurName): HealthStatus
{
$health = HealthStatus::HEALTHY;
$client = HttpClient::create();
$response = $client->request(
method: 'GET',
url: 'https://api.github.com/repos/SymfonyCasts/dino-park/issues'
);
foreach ($response->toArray() as $issue) {
if (str_contains($issue['title'], $dinosaurName)) {
$health = $this->getDinoStatusFromLabels($issue['labels']);
}
}
return $health;
}
// ... lines 29 - 49

Hmm... Bueno, ¡creo que lo hemos conseguido! Hagamos nuestras pruebas para estar seguros.

./vendor/bin/phpunit

Y... ¡Vaya! Tenemos 8 pruebas, 11 afirmaciones, ¡y todas pasan! ¡Shweeet!

Registra todas nuestras peticiones

¡Un último reto! Para facilitar la depuración, quiero registrar un mensaje cada vez que hagamos una petición a la API de GitHub.

¡No hay problema! Sólo tenemos que obtener el servicio logger. Añade un constructor conprivate LoggerInterface $logger para añadir un argumento y una propiedad de una vez. Justo después de llamar al método request(), añade $this->logger->info() y pasaRequest Dino Issues para el mensaje y también un array con contexto extra. ¿Qué tal una clave dino establecida en $dinosaurName y responseStatus en$response->getStatusCode().

59 lines | src/Service/GithubService.php
// ... lines 1 - 5
use Psr\Log\LoggerInterface;
// ... lines 7 - 8
class GithubService
{
public function __construct(private LoggerInterface $logger)
{
}
public function getHealthReport(string $dinosaurName): HealthStatus
{
// ... lines 17 - 25
$this->logger->info('Request Dino Issues', [
'dino' => $dinosaurName,
'responseStatus' => $response->getStatusCode(),
]);
// ... lines 30 - 37
}
// ... lines 39 - 57
}

¡Genial! Eso no debería haber roto nada en nuestra clase, pero ejecutemos las pruebas para estar seguros:

./vendor/bin/phpunit

Y... ¡Ay! ¡Sí que hemos roto algo!

Demasiados pocos argumentos pasados al constructor en GithubService. se esperaban 0 pasados 1.

¡Por supuesto! Cuando añadimos el argumento LoggerInterface a GithubService, nunca actualizamos nuestra prueba para pasarlo. A continuación te mostraré cómo podemos hacerlo utilizando una de las superhabilidades de PHPUnit: el mocking.