Script en Bash y cURL para hacer comprensiva una API | Programador Web Valencia

Script en Bash y cURL para hacer comprensiva una API

3 minutos

Bash script vs Postman

Documentar una API, por mucho detalles que incluyas, siempre será insuficiente si no incluyes ejemplos de uso. Y si además son reales, que puedes ejecutar para obtener resultados, sus campos son configurables y todos los detalles técnicos se encuentran a la vista (sin magia), el equipo de desarrollo te hará la ola.

Quienes hemos trabajado con Postman, o softwares similares, sabemos que es una herramienta muy útil para probar APIs. Pero también para dejar ejemplos funcionales de su uso. No obstante, Postman posee limitaciones a largo plazo:

  • Si quieres compartir tus ejemplos con muchos compañeros de trabajo, tendrás que pagar una suscripción.
  • Tus ejemplos, o documentación interactiva, esta atada a un software de terceros.
  • No es fiable a largo plazo, ya que con las diferentes versiones de Postman, los ejemplos pueden dejar de funcionar.

Por ello recomiendo usar algún lenguaje de script, que sea un estándar en la industria y sea fácil de ejecutar en cualquier sistema operativo. Bash con cURL son una combinación explosiva. Y si además añades jq para formatear la salida JSON, tendrás una herramienta similar a Postman, pero sin sus desventajas.

Por lo tanto, los requisitos mínimos será tener instalado bash (suele ya estar por defecto en entornos de desarrollo), curl y jq.

Get

El siguiente ejemplo es un script en Bash que hace una petición GET.

Los parámetros son en la URL, por lo que se deben codificar. Para ello se ha creado una función urlencode.

  • COMPANY_NAME: Nombre de la empresa.
  • APP_NAME: Nombre de la aplicación.
  • EMAIL: Email del usuario.
#!/usr/bin/env bash
set -o errexit

urlencode() {
    # urlencode <string>

    old_lc_collate=$LC_COLLATE
    LC_COLLATE=C

    local length="${#1}"
    for (( i = 0; i < length; i++ )); do
        local c="${1:$i:1}"
        case $c in
            [a-zA-Z0-9.~_-]) printf '%s' "$c" ;;
            *) printf '%%%02X' "'$c" ;;
        esac
    done

    LC_COLLATE=$old_lc_collate
}

# Parameters
COMPANY_NAME=$(urlencode "Foo")
APP_NAME=$(urlencode "Boo")
EMAIL="foo@example.com"

# Endpoint
METHOD='GET'
ENDPOINT="company/${COMPANY_NAME}/app/${APP_NAME}/users/${EMAIL}"

# Request
curl -s -L -X $METHOD -G \
  "http://localhost:8000/api/v1/${ENDPOINT}" \
  | jq .

Se ha separado el método y el endpoint en variables para que sea más fácil de modificar.

Por último, se ha añadido jq . para formatear la salida JSON.

Post

Se pretende enviar un JSON en el cuerpo de la petición. Para ello se ha creado una variable BODY con el JSON a enviar. Se incluye la cabecera Content-Type: application/json para indicar que el cuerpo de la petición es un JSON.

#!/usr/bin/env bash
# exit on error
set -o errexit

urlencode() {
    # urlencode <string>

    old_lc_collate=$LC_COLLATE
    LC_COLLATE=C

    local length="${#1}"
    for (( i = 0; i < length; i++ )); do
        local c="${1:$i:1}"
        case $c in
            [a-zA-Z0-9.~_-]) printf '%s' "$c" ;;
            *) printf '%%%02X' "'$c" ;;
        esac
    done

    LC_COLLATE=$old_lc_collate
}


# Parameters
COMPANY_NAME=$(urlencode "Foo")
APP_NAME=$(urlencode "Boo")
BODY='{
	"email": foo@example.com",
  	"password": "password",
  	"firstName": "Foo",
  	"lastName": "Boo",
  	"isEnabled": true,
  	"role": "admin"
}'

# Endpoint
METHOD='POST'
ENDPOINT="company/${COMPANY_NAME}/app/${APP_NAME}/users/"

# Request
curl -s -L -X $METHOD \
  "http://localhost:8000/api/v1/${ENDPOINT}" \
  --header "Content-Type: application/json" \
  --data "$BODY" \
  | jq .

El resto del script es similar al anterior.

Mostrando el tiempo de respuesta

Es importante medir el rendimiento de la API, y si puede ser en milisegundos mucho mejor. Para ello podemos incluir una pequeña actualización en el script.

Al inicio guardamos el tiempo actual.

start=$(date +%s%3N)

Y al final del script, volvemos a guardar el tiempo actual y restamos el tiempo inicial.

end=$(date +%s%3N)    # Record end time in milliseconds
execution_time=$((end - start))  # Calculate the difference in milliseconds
echo "Execution time: ${execution_time} milliseconds"

Debajo del JSON aparecerá el tiempo de respuesta en milisegundos.

Todo unificado al ejemplo GET quedaría así:

#!/usr/bin/env bash
set -o errexit

start=$(date +%s%3N)

urlencode() {
    # urlencode <string>

    old_lc_collate=$LC_COLLATE
    LC_COLLATE=C

    local length="${#1}"
    for (( i = 0; i < length; i++ )); do
        local c="${1:$i:1}"
        case $c in
            [a-zA-Z0-9.~_-]) printf '%s' "$c" ;;
            *) printf '%%%02X' "'$c" ;;
        esac
    done

    LC_COLLATE=$old_lc_collate
}

# Parameters
COMPANY_NAME=$(urlencode "Foo")
APP_NAME=$(urlencode "Boo")
EMAIL="foo@example.com"

# Endpoint
METHOD='GET'
ENDPOINT="company/${COMPANY_NAME}/app/${APP_NAME}/users/${EMAIL}"

# Request
curl -s -L -X $METHOD -G \
  "http://localhost:8000/api/v1/${ENDPOINT}" \
  | jq .

end=$(date +%s%3N)    # Record end time in milliseconds
execution_time=$((end - start))  # Calculate the difference in milliseconds
echo "Execution time: ${execution_time} milliseconds"

Apuntes finales

El objetivo no es crear una batería de tests para la API, ya hay lenguajes y librerías mucho más potentes para ello (como pytest con requests en Python). Nos centraremos en tener ejemplos funcionales, fáciles de compartir (pueden estar en el mismo repositorio de la API), resistentes a lo largo del tiempo y libres de software de terceros. Y nada mejor para ello que usar herramientas Unix.

Puedes llevar elementos repetitivos a ficheros externos que puedes invocar con source. O incluso crear funciones para cada petición, que reciban los parámetros necesarios. Lo dejo a tu elección. Pero recuerda, la simplicidad es la clave.

Por último, documentar acompañando la API con ejemplos autogenerados (como OpenAPI o Swagger) es una buena práctica. Sin embargo, te estas dejando atrapar por un framework. Recuerda, divide y vencerás.

Esta obra está bajo una Licencia Creative Commons Atribución-NoComercial-SinDerivadas 4.0 Internacional.

Atribución/Reconocimiento-NoComercial-SinDerivados 4.0 Internacional

¿Me invitas a un café? ☕

Puedes hacerlo usando el terminal.

ssh customer@andros.dev -p 5555

Comentarios

{{ comments.length }} comentarios

Nuevo comentario

Nueva replica  {{ formatEllipsisAuthor(replyComment.author) }}

Acepto la política de Protección de Datos.

Escribe el primer comentario

Tal vez también te interese...