DEV Community

Cover image for #CienDiasConCourseIt: Día 6/100
Javier Rodriguez
Javier Rodriguez

Posted on • Updated on

#CienDiasConCourseIt: Día 6/100

HTTP y fetch. API de GitHub

Resumen

Por el titulo parecerá poco, pero lo que más me consumió tiempo fue implementar el último ejercicio en donde consumimos la API de GitHub para elaborar un buscador de perfiles. El protocolo HTTP es esencial para entender a realizar este tipo de ejercicios. Pero como sé que aburre un poco la teoría, no me extendí demasiado!

Podrás ver la lista de los 100 días en este enlace.

HTTP

HTTP es un protocolo para transmitir información a través de la web. El Frontend de una página, va a buscar información de un Backend que almacena en una base de datos. El Backend le devuelve como respuesta esta información requerida.

El cliente va a realizar una HTTP Request al servidor, y el servidor va a devolver la información requerida.

HTTP tiene métodos o protocolos para poder realizar estas request, que son: GET, POST, PUT y DELETE (entre otros):

  • GET es para pedir información
  • POST es para enviar información
  • PUT es para actualizar información
  • DELETE es para borrar información

Hay un concepto similar que es CRUD (Create, Read, Update, Delete).
Junto con los protocolos HTTP, existen los códigos de estado:

  • 20x Todo está bien :D
  • 30xx Redirección :)
  • 40x Errores de parte del cliente :(
  • 50x Errores de parte del servidor :s

fetch

Es una manera de hacer peticiones HTTP para acceder a información.
API es como un array de objetos que nos devuelve un servidor. Este formato de arrays se lo conoce como JSON. Vamos a tratar de conectarnos a la API de GitHub.

Veamos primero como se escribe un fetch:

async function fetchData () {
    const data = await fetch('https://api.github.com/users/JaviCeRodriguez'); // Petición GET (por defecto) al endpoint (la url)
    const json = await data.json(); // Transforma un array de datos en formato JSON

    console.log(json);
}

fetchData()
Enter fullscreen mode Exit fullscreen mode

Hay un concepto que debemos saber y es sobre sincronismo y asincronismo. Con sincronismo, realizamos peticiones (por ejemplo) y esperamos a obtener alguna respuesta para poder continuar con otra tarea. Con asicronismo, realizamos peticiones y podemos hacer otra cosa mientras.
fetch es asincrónico porque necesitamos realizar las peticiones a algún servidor y no sabemos el tiempo que puede tardar en obtener respuesta.
Una promise es una promesa de que alguna información que va a volver o que va a volver algún error.
async y await es parecido a una promesa pero se escribe distinto. Usamos async en la función para indicarle a la función que debe esperar una respuesta de forma asincrónica. Usamos await para indicar que parte de nuestra función es asincrónica (data y json).
Utilizamos async y await para eliminar las rise condtions, es decir, evitamos que nuestra función sea más rápida que la respuesta del servidor.

Armaremos algo copado: Buscador de perfiles de GitHub!

<!-- En HTML -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>GitHub Profile Finder</title>
</head>
<body>
    <section class="welcome">
        <h2>Welcome to the GitHub Profile Finder</h2>
        <p>
            This search engine will help you find profiles quickly just by
             knowing the user. Use the GitHub API to get the profile
              information.</p>
    </section>

    <div class="search flex">
        <div class="inputProfile flex">
            <label>User: </label>
            <input type="text" name="search" id="userGH" placeholder="Type user..." />
        </div>
        <button onclick="fetchData()">Search profile</button>
    </div>

    <div id='dataProfile' class="dataProfile flex">
        <!-- Foto de Perfil -->
        <figure class="flex">
            <img id='imgProfile' src="" alt="imgProfile">
        </figure>
        <!-- Labels -->
        <div class="infoText flex">
            <label>Name: <span id="name"></span></label>
            <label>Location: <span id="loc"></span></label>
            <label>Bio: <span id="bio"></span></label>
            <label>Twitter: <span id="twProfile"></span></label>
            <label>User: <span id="user"></span></label>
        </div>
    </div>

    <div id="state" class="state">
        <h1 id="stateHTTP"></h1>
    </div>

    <footer>
        Made by <a href="https://github.com/JaviCeRodriguez" target="_blank">Javier Rodriguez</a> with many 🧉 - January 2021
    </footer>

    <script src="./appScript.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode
// En CSS
body{
    margin: 0;
    padding: 0;
    font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
    background-color: #06090f;
    color: white;
}

.flex{
    display: flex;
}

label{
    font-weight: 500;
}

.welcome{
    width: 80%;
    margin: auto;
    text-align: center;
}

.search{
    flex-direction: row;
    justify-content: space-evenly;
    align-items: center;
    margin: auto;
    margin-bottom: 1rem;
    width: 80%;
    padding: 1rem 0.2rem;
    background-color: #161b22;
    border: 1px solid #30363d;
    border-radius: 0.5rem;
}

.search .inputProfile{
    justify-content: center;
    align-items: center;
}

.search .inputProfile input{
    background-color: #0d1117;
    border: 1px solid #30363d;
    border-radius: 0.4rem;
    margin: 0.5rem;
    padding: 0.3rem 0.6rem;
    color: white;
}

.search button{
    width: 10rem;
    padding: 0.8rem;
    background-color: #238636;
    border: none;
    border-radius: 0.2rem;
    color: white;
    font-weight: 600;
    cursor: pointer;
}

#dataProfile{
    display: none;
}

.dataProfile{
    justify-content: center;
    margin: auto;
    padding: 1rem 0.2rem;
    width: 80%;
    background-color: #0d1117;
    border: 1px solid #30363d;
    border-radius: 0.5rem;
}

.dataProfile figure{
    width: 40%;
    justify-content: center;
}

.dataProfile figure img{
    width: 230px;
    height: 230px;
    border: 1px solid #30363d;
    border-radius: 50%;
}

.dataProfile .infoText{
    flex-direction: column;
    justify-content: center;
    width: 60%;
    padding: 0.8rem;
}

.dataProfile .infoText label{
    padding-bottom: 0.5rem;
}

.dataProfile .infoText label span{
    font-weight: normal;
    padding-left: 0.2rem;
}

#state{
    display: none;
}

.state h1{
    text-align: center;
    padding: 1rem;
}

footer{
    padding: 1rem;
    width: 80%;
    margin: auto;
    text-align: center;
    font-size: 0.8rem;
}

footer a{
    text-decoration:none;
    color: white;
    font-weight: 600;
}
Enter fullscreen mode Exit fullscreen mode
// En JavaScript
async function fetchData () {
    const inputValue = document.getElementById('userGH').value;
    const data = await fetch(`https://api.github.com/users/${inputValue}`);
    const json = await data.json();
    const img = document.getElementById('imgProfile');
    const idArray = ['name', 'loc', 'bio', 'twProfile', 'user'];
    const jsonArray = [json.name, json.location, json.bio, json.twitter_username, json.login];

    if(data.status != 404){
        console.log(json);
        document.getElementById('dataProfile').style.display = 'flex';
        document.getElementById('state').style.display = 'none';
        img.setAttribute('src', json.avatar_url);
        for (let i = 0; i < idArray.length; i++){
            validData(idArray[i], jsonArray[i]);
        }
    } else{
        document.getElementById('dataProfile').style.display = 'none';
        document.getElementById('state').style.display = 'inline';
        const error = `${data.status} Error! 😿
        Try another valid user`;
        document.getElementById('stateHTTP').innerText = error;
    }
    document.getElementById('userGH').value = '';
}

function validData(idElement, data){
    if (data === null || data === ''){
        document.getElementById(idElement).innerText = '-';
    } else{
        document.getElementById(idElement).innerText = data;
    }
}
Enter fullscreen mode Exit fullscreen mode

Aprovecho la variable data para realizar un chequeo de con qué código de estado estamos obteniendo la información de la API. Si nos tira un 404, es porque no existe o no es válido el usuario.
También implemento un par de arrays y bucle for para optimizar un poco el script y jugamos con las propiedades display para mostrar un solo div dependiendo de qué código de estado obtengamos.

Pueden ver este ejercicio desplegado en Vercel acá.


Día 6/100

Top comments (0)