Archivo de la etiqueta: cli

Odio Postman: Alternativas en software libre (de verdad) al asqueroso Postman

¿Por qué odio Postman?

  • Porque no es software libre de verdad. Nada mas abrirlo te pide registrate en su servicio online, si no viene capado de serie. Hay otros proyectos de software libre como NextCloud que te dan la alternativa de usar «su nube» o no, pero estos no, son rollo JetBrains de repartir droga a la puerta del colegio en busca de nuevos jonkis.
  •  Bloadware, ya sabéis y no lo sabéis ahora os lo digo, soy fan de la filosofía kiss y suckless. Y el puñetero Postman es un bicho de casi 200 mb (porque tiene Electron dentro) para un interfaz incomible.
  • No es fácil de usar. ¿Cómo se hace para meter un JWT de forma fácil y automática? Supongo que tendrá algo parecido a pipelines pero no lo he encontrado. Y lo peor, te obliga (porque es Electron) a usar javascript si quieres scriptarlo.

Alternativas CLI a Postman

Dicho esto, que soluciones tenemos para jugar con API RESTFul y cositas en swagger en GNU/Linux. Ya sabéis, es lo que toca cuando eres fullstack engineer o un doctor brown.

OJO aviso (para evitar sustos): La lista de alternativas son CLI por que, digan lo que digan con un –help y autocompletado (usa tu amiga la tecla tabulador) cualquier herramienta CLI le da mil vueltas en facilidad a cualquier herramienta de botoncitos y dando vueltas con el ratoncito, además menos es mas, y cuanto menos CPU, RAM y disco duro te consuma la herramiento mejor.

  • Curl : el viejo y confiable curl te saca de un aprieto como netcat  o telnet sin pedirte nada a cambio, es que son un primor.
    • (ventaja/pro) viene en todas las distribuciones de GNU/Linux de base sin instalar nada y en casi todos los lenguajes de script python, etc. Entonces es un estándar.
    • (desventaja/contra) es un caos los parámetros…aunque cuando te haces un par de snippets o recetas con los que mas usas, vives feliz…el problema cuando quieres hacer algo raro. Truco: Firefox o Chromium si no conoces el panel de depuración web…ya estas tardando, porque en la pestaña de «network» puedes ver las llamadas al API y copiar/guardar «as Curl».
  • HTTPie : Le tengo mucho cariño a esta herramienta porque con cuatro lineas de bash puedes hacer cualquier cosa contra un API.
    • (ventaja/pro) es muy muy fácil de usar, la descripción del proyecto es «CLI, cURL-like tool for humans».
    • (desventaja/contra) bueno para algunos es que «es python» pero bueno estreñidos hay por el mundo además en Debian hay paquete httpie y si hay paquete en Debian es un estándar y punto.
  • HTTP Prompt: Es un subproyecto de la gente de HTTPie, la pena es no le dan muchos mimos a este proyecto y tiene fallos, pero es super curioso como plantea el API como si fuera un árbol de directorios.
    • (ventaja/pro) es muy fácil de usar y puede comerse el «spec» del API para autogenerar el CLI.
    • (desventaja/contra) esta un pelín verde y tiene fallos.

Como usar HTTPie

Primero hay que instalarlo, puedes o desde pip :

$ sudo pip3 install -U httpie

O desde (si es Debian o alguna derivada como Ubuntu o Linux Mint):

$ sudo apt install httpie

Hay un plugin muy interesante para soportar jwt que mas o menos es un estándar de login y mantenter sesión para comunicarse con APIs aunque hay plugins para mas estándares como Oauth2 y así. Para instalarlo, este si es necesario de momento pip porque no esta empaquetado en Debian:

$ sudo pip3 install -U httpie-jwt-auth

Aunque en algún ejemplo siguiente te enseñare que casi no es necesario mas que para ahorrase unas lineas en bash.

Por cierto la combinación httpie + jq es mucho mejor que el melón con jamón. Si no conoces jq ya estas tardando porque es el como un grep hipervitaminado de los json.

la sintaxis de httpie es:

http <verbo POST|PUT|GET> <url_endpoint> <parámetros header|get|post> <opciones_httpie>

Ejemplos con HTTPie

Usando como base publicapis.org que es un proyecto muy interesante que guarda y lista APIs públicas de muchos tipos.

Vamos a poner un par de ejemplos reales:

Sacar las categorías de publicapis

Tan simple como lanzarle un get a la enpoint de categorías

$ http get https://api.publicapis.org/categories
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Length: 716
Content-Type: application/json
Date: Sun, 17 Oct 2021 21:22:49 GMT
Server: Caddy
X-Rate-Limit-Duration: 1
X-Rate-Limit-Limit: 10.00
X-Rate-Limit-Request-Forwarded-For: 89.219.91.239
X-Rate-Limit-Request-Remote-Addr: 172.17.0.1:49224

[
    "Animals",
    "Anime",
    "Anti-Malware",
    "Art & Design",
    "Authentication",
    "Blockchain",
    "Books",
    "Business",
    "Calendar",
    "Cloud Storage & File Sharing",
    "Continuous Integration",
    "Cryptocurrency",
    "Currency Exchange",
    "Data Validation",
    "Development",
    "Dictionaries",
    "Documents & Productivity",
    "Entertainment",
    "Environment",
    "Events",
    "Finance",
    "Food & Drink",
    "Games & Comics",
    "Geocoding",
    "Government",
    "Health",
    "Jobs",
    "Machine Learning",
    "Music",
    "News",
    "Open Data",
    "Open Source Projects",
    "Patent",
    "Personality",
    "Phone",
    "Photography",
    "Science & Math",
    "Security",
    "Shopping",
    "Social",
    "Sports & Fitness",
    "Test Data",
    "Text Analysis",
    "Tracking",
    "Transportation",
    "URL Shorteners",
    "Vehicle",
    "Video",
    "Weather"
]

Y por ejemplo usando jq para sacar la lista de API relacionados con la música los parámetros get se ponen como == :

$ http https://api.publicapis.org/entries category=="Music" | jq ".count"
31

Guardar el json de los API relacionados con la música

$ http https://api.publicapis.org/entries category=="Music" > /tmp/music.json

Y revisando el listado me fije que teniamos a mi querido jamendo pero también se puede filtrar con ayuda de jq la entrada de este proyecto de música libre:

$ http https://api.publicapis.org/entries category=="Music" | jq '.entries | .[] | select(.API=="Jamendo")'

Y para hacer un post de un formulario los parámetros se separan con = , la gente de httpie tiene un api simple para hacer pruebas:

$ http --form POST pie.dev/post name='John Smith'
HTTP/1.1 200 OK
CF-Cache-Status: DYNAMIC
CF-RAY: 69fd13e64d786611-MAD
Connection: keep-alive
Content-Encoding: gzip
Content-Type: application/json
Date: Sun, 17 Oct 2021 22:49:01 GMT
NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=FhO29LNgr1Dn0bY%2FDOESxrq5o%2BR5tePJpkCOElIS0asl4hDNC6uhN%2F8EYa4NU37kSUEqfMrHvKt6OMJh4s4rZ4BCSPQawxVVpT%2FQ0Q1KJAfq%2FcIG0yn01Zop"}],"group":"cf-nel","max_age":604800}
Server: cloudflare
Transfer-Encoding: chunked
access-control-allow-credentials: true
access-control-allow-origin: *
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400

{
    "args": {},
    "data": "",
    "files": {},
    "form": {
        "name": "John Smith"
    },
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip",
        "Cdn-Loop": "cloudflare",
        "Cf-Connecting-Ip": "87.219.94.239",
        "Cf-Ipcountry": "ES",
        "Cf-Ray": "69fd13e64d786611-FRA",
        "Cf-Visitor": "{\"scheme\":\"http\"}",
        "Connection": "Keep-Alive",
        "Content-Length": "15",
        "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
        "Host": "pie.dev",
        "User-Agent": "HTTPie/2.6.0"
    },
    "json": null,
    "origin": "87.219.94.239",
    "url": "http://pie.dev/post"
}

Hacer un post de un json a un API, yo lo hago en dos partes para trabajar tranquilamente en el terminal:

$ json="{\"name\": \"pepito\", \"description\": \"El pinocho.\", \"color\": \"shitbrown\"}"
$ echo "$json" | http POST http://127.0.0.1:8080/api/v1/prueba

Y subir un fichero es tan simple (en comparación con curl) como, donde fichero es nombre del parámetro de fichero:

$ http POST "http://127.0.0.1:8080/api/v1/uploads/" fichero@"file.png"

Si necesitas cookies o guardar algún tipo de sesión, lo puedes hacer como por ejemplo:

$ http --session=/tmp/caca.json POST http://127.0.0.1:8080/api/v1/auth

Y después el típico jwt lo puedes hacer a mano con por ejemplo:

user="usuario"
password="mi voz es mi pasaporte, verifícame"

$ passhash=$(echo -n "$password" | sha256sum | cut -d" " -f1)
$ jwt=$(echo "{ \"username\": \"$user\", \"password\": \"$passhash\" }" | http POST http://127.0.0.1:8080/api/v1/auth | jq .token -r)

En este ejemplo ya con ayuda de jq he metido en la variable $jwt el token para usarlo por ejemplo en las siguientes llamadas:

$ http GET http://127.0.0.1:8080/api/v1/caballos Authorization:"Bearer $jwt"

El parámetro Authorization es un parametro del header que le mandamos, httpie lo detecta por el : .

Y ahí le metemos tal cual dice el estandár de jwt el token de autorización.

Pero también se puede hacer con el plúgin httpie-jwt-auth mas sencillo y con menos lineas:

$ http GET http://127.0.0.1:8080/api/v1/caballos --auth-type=jwt --auth="$jwt"

O metiendo la variable como variable de entorno

$ export JWT_AUTH_TOKEN=$jwt
$ http GET http://127.0.0.1:8080/api/v1/caballos --auth-type=jwt

Y los script en bash es que son tan legibles con httpie, porque empiezas con un login y después con la ristra de acciones que tienes que ir haciendo.