API Rest
Conceptos
Agenda
• Introducción.
• Fetch, Promesas, async/await.
• API REST.
• Un paso más (GraphQL, WebSockets).
Introducción
Entender la web
Cómo funcionaba la web…
Pedías una página que venía “completa” desde el servidor:
<form method=”post" >
<input id="email" type="email" />
<input id=”pwd" type="password" />
<button type="submit">
Submit
</button>
</form>
POST / HTTP/1.1
Host: [Link]
Content-Type: application / x-www-form-urlencoded
Content-Length: 13
email = [Link]@[Link] & pwd = password1
¿ Es esto práctico?
Veámoslo con un ejemplo, una web de reservas de hotel a nivel mundial
con un buscador que te permite elegir, hotel, ciudad, país, barrio….
Se pueden hacer millones de búsquedas
Quieres que conforme el usuario teclea se
afine el resultado
¿ Te imaginas ir haciendo un form post por
cada tecla que pulsa el usuario?
Esto se traduce en Euros, más usabilidad
más venta
Cómo se usan los formularios hoy
Aprovechamos el tag, pero el submit nunca se envía a servidor.
<form
onSubmit={(e) => {[Link]();Save();}}>
<input id="username"/>
<input id="password"/>
<button type="submit">login</button>
</form>
¡ Anda ! Ahora entiendo lo
del “preventDefault” que se
le ponía a cada formulario
AJAX – XMLHttpRequest
Lo introdujo Microsoft en IE5 y mozilla lo incluyó en 2002, nos permite
hacer llamadas asíncronas desde una web a un servicio, no más
limitaciones de posts.
Salió por su cuenta en modo “salvaje”, no se empezó a estandarizar hasta
2006
Ha sido la base para hacer llamadas asíncronas (A JAX) en sitios tales
como Gmail,
Por cierto, termino A JAX → Asynchronous Javascript and XML
¿ Qué tiene que ver esto hoy en día con XML? Nada ☺
¿ Eso se usa hoy en día?
Seguramente estés usándolo sin saberlo en alguno de tus proyectos ☺
En librerías En polyfills
Un polyfill es un parche que te permite
Tu usas abstracciones y wrappers usar algo moderno en un navegador
antiguo
Por ejemplo chequea si existe “fetch” y
Por dentro llaman a XMLHttpRequest
si no añade una implementación
¿Un ejemplo? Axios Esta implementación usa bajo el capó
Ver libs/adapters/[Link] XMLHttpRequest
Ejemplo time
¡¡ A los teclados !!
Desventajas
No es fácil de usar, la web de ahora no es la de hace 15 años
Cada navegador lo implementó a su manera
Lo ideal es usar métodos más modernos (por ejemplo fetch)
También puede usar librerías que por ejemplo lo “promisifican”
Modernos…
Promesas, Fetch, Async Await
Callbacks
Los callbacks son la pieza clave para que JavaScript pueda funcionar de forma
asíncrona. De hecho, el resto de patrones asíncronos en JavaScript está basado en
callbacks de un modo u otro, añadiendo azúcar sintáctico.
Un callback no es más que una función que se pasa como argumento de otra función,
y que será invocada para completar algún tipo de acción
setTimeout(function () {
[Link]("Esto debería aparecer primero");
}, 500);
[Link]("Sorpresa!");
// Sorpresa!
// Esto debería aparecer primero
Callbacks
var getJSON = function (params) {
sendAjax({ El callback se convierte en un problema si
type: "get", tenemos que anidar varias llamadas
url: [Link],
success: function (res) {
[Link] &&
[Link]( No podemos esperar a que termine una
[Link](res) llamada en varios puntos de la aplicación
);
},
}); Si queremos esperar a que varias llamadas
}; terminen a la vez, tenemos que
“inventarnos” algo
El manejo de errores es un poco pesado
Promesas
Una promesa es un objeto que representa el resultado de una operación asíncrona.
Este resultado puede estar disponible ahora o en el futuro. Las promesas se basan en
callbacks pero añaden azúcar para un mejor manejo y sintaxis.
Una funcionalidad muy interesante es la de poder encadenar promesas, por ejemplo
en este código recibimos la respuesta, pedimos que nos la procese como JSON y acto
seguido ya puede leer los datos
fetch([Link]
.then(response => [Link]())
.then(data => [Link](data))
.catch(error => [Link](error));
Async Await
Async / Await es un azúcar sintáctico que se monta sobre las promesas, permite
escribir código asíncrono como si fuera código secuencial
Tenemos que marcar la función que va a tener asincronía como async y la línea
donde llamemos a llamada asíncrona como await.
Cómo funciona esto es que cuando se ejecuta la llamada con await se para la
ejecución de esa función hasta que no recibe la respuesta de la promesa
const checkServerWithSugar = async (url) => {
const response = await fetch(url);
return `Estado del Servidor: ${[Link] === 200 ? "OK" : "NOT OK"}`;
};
API Rest
No solo de get vive el hombre
Organizando el acceso
Acceder a un end point de prueba y sacar datos de un servidor está bien, ¿
pero que debemos tener en cuenta en un proyecto real?
Mi servicio puede ser Si salto a otro Mi capa de servicios
consumido por proyecto, debería de tiene que estar
múltiples lenguajes y tener unas bases preparada para
tecnologías comunes asentadas escalar
Los datos tiene que viajar en un formato que cualquier lenguaje pueda leer o
fácilmente parsear
Debe haber una forma estándar de definir las urls a los datos que quiero
acceder, así como las operaciones que quiera realizar
Si mi capa de servicios tiene que almacenar el estado del usuario voy a tener
problemas para escalar
REST API
El termino REST (Representational State Transfer) lo acuñó Roy Fielding
(padre de la especificación HTTP) en el año 2000. Son uno conjunto de
restricciones que me permiten crear api’s para consumir desde HTTP.
Los datos normalmente viajan en formato JSON (fácil de consumir), nos da igual la
tecnología de servidor y la de cliente
Define unos verbos básicos para realizar entre otros inserciones, actualizaciones y
borrados (GET, PUT, POST, DELETE…)
Establece una definición de URLs por recurso que hace fácil poder saltar de
proyecto y entender como está organizada
No tiene estado, cada petición al servidor es independiente, al no tener sesión está
preparado para escalar en horizontal
Limitaciones REST API
El estándar de API tiene ya 20 años, fue una revolución en su día, pero ya va
pidiendo un reemplazo.
La estructura es rígida y no siempre se adapta a lo que necesitas
Al final acabas creando métodos en los que haces “trampas” para acceder a queries
específicas
Muchas veces te hace falta mezclar resultados de varios endpoints, si tener que
hacer varios viajes a servidor o hacer un cherry pick de los campos a mostrar
GraphQL se está erigiendo como el nuevo estándar de facto para solucionar
algunas limitaciones de REST API
URLs
API REST
Definiendo URLs
Siempre estamos tentados a definir URLs como…
getAllBooks
createBook
deleteBookById
Pero estamos definiendo un montón de URLs diferentes e incluso al ser
nombres muy largos, dificulta la legibilidad. Y si…
Pudiésemos definir URLs más cortas
Indicarle el verbo para realizar diferentes acciones
Proveer diferentes parámetros
URLs
Cuando hacemos la llamada a un endpoint, estamos accediendo a
recursos.
/books
/<recurso> /authors
Definición
/books/:id
/authors/:name
/<recurso>/:<param>
Uso
/books/2
/authors/j-k-rowling
URLs
Más aproximaciones… Definición
OJO!
No replicar BBDD /books/:id/reviews
/<recurso-1>/:<param> /<recurso-2>
Uso
/books/2/reviews
Excepciones…
/login /logout /activate …
Ventajas / desventajas
URLs mas cortas
Acceso a un recurso en concreto
No siempre se adapta
Se puede reutilizar para diferentes acciones
Verbos HTTP
API REST
Verbos HTTP
Ya tenemos definidos los recursos, pero quiero hacer diferentes acciones.
Los verbos principales, conocido como CRUD (Create, Read, Update, Delete)
/books
GET Recuperar recursos
/books/:id
POST Crear nuevos recursos /books
PUT Actualizar recursos /books/:id
DELETE Borrar recursos /books/:id
Más verbos
HEAD Idéntico al GET pero sin el body de la respuesta.
Igual que el PUT, pero actualizando un subconjunto de
PATCH
campos.
Preguntar configuración servidor: métodos permitidos,
OPTIONS configuración CORS, tiempo cache, etc.
CONNECT Conexiones con servidores proxy
… Reference: [Link]
Extension WebDAV: [Link]
Parámetros
API REST
Parámetros
Hay varias formas de enviar parámetros a servidor…
/books/:id /books/20
URL Params /<recurso>/:<param>
Aquí no hace falta definir que parámetros
existen cuando se defina la url.
Query /<recurso>?<param>=<value> /books?name=cancion-de-hielo-y-fuego
Params
/books?sort=name,review
/<recurso>?<param1>=<value1>&<param2>=<value2> /books?q=cancion%20de%20hielo
/books?page=2&pageSize=10
URLs con espacios
Definiendo urls con espacios y caracteres raros…
URL poco amigables
[Link] path/ -> [Link]
Penalizan SEO
Normalmente usados en Query Params
Hay que usar encodeURI / decodeURI
Parámetros
Otro tipo de parámetros…
POST /login HTTP/1.1
Host: [Link]
// Headers
Body Params Content-Type: application/json
// Body
{ “user”: “admin”, “password”: “test” }
GET /books HTTP/1.1
Host: [Link]
Headers
// Headers
Authorization: Bearer eyJhoIFGoioij…
GET /books HTTP/1.1
Host: [Link]
Cookies
// Headers
Set-Cookie: my-cookie=cookie-value
Respuesta
API REST
HTTP status codes
Necesitamos informar a cliente de que ha pasado con su petición
1xx Respuestas informativas 101 102 …
2xx Respuestas con éxito 200 201 204 …
301
3xx Redirección 307 304 …
308
4xx Error de cliente 404 401 403 …
5xx Error de servidor 500 501 503 …
Reference: [Link]
Responses
Además del status code
Headers
Content-Type Header
Payload
HTTP/1.1 200 OK HTTP/1.1 200 OK
Date: Mon, 09 Jun 2021 12:00:00 GMT …
Content-Type: text/html Content-Type: application/json
<!DOCTYPE html … { “id”: 1, “name”: “John” }
Demo time
¡¡ A los teclados !!
Un paso más
Graph QL, Web Sockets
GraphQL
Las APIs REST son rígidas, definen una serie de endpoints y estructuras , ¿ Qué
pasa si me hacen falta menos campos o combinar dos consultas? Me acabo
creando API’s AdHoc
¿ Y si tuviera un único endpoint en el que yo defino que resultados y campos
necesito? Eso es GraphQL ☺
Web Sockets
Enviar peticiones HTTP para traernos datos está bien para muchos
escenarios, ¿Pero y si me hace falta tiempo real? Por ejemplo, leer valores
de acciones de bolsa, o interactuar en un juego online.
Podría intentar hacer peticiones HTTP cada X segundos (polling), pero puedo
acabar ahogando el servidor y tampoco la respuesta es fluida
Lo ideal sería establecer un canal bidireccional de comunicación que estuviera
siempre abierto
Desde ese canal me puedo suscribir a una sala e ir recibiendo actualizaciones
También puedo escribir al mismo
Aquí entran en juego los Web Sockets !!
¡ Muchas gracias !
@lemoncoders @basefactorteam
[Link]