Bruno è un API Client open source che, ormai da qualche tempo, si sta rapidamente diffondendo, guadagnando terreno nei confronti del popolarissimo Postman.
Si tratta di un progetto che vuole crescere con il supporto della propria Community, senza la partecipazione di aziende terze (se non come sponsor) e, soprattutto, con la forte volontà di non farsi acquisire. Insomma, vogliono camminare con le loro gambe, mantenendo la propria identità, accettando aiuti esterni, senza però permettere alcuna interferenza nella gestione del progetto.
Di questi tempi è certamente un nobile intento, auguriamoci che duri.
Perché Bruno
Non so per voi ma, per me, Postman è da sempre sinonimo di “affidabilità” e “abitudine”: nonostante alcuni piccoli dettagli (ad esempio il non poter modificare le request se non attraverso la sua interfaccia) l’ho sempre trovato adatto a quelle che sono le mie esigenze. La mia caratteristica pigrizia ha fatto il resto: tutte le mie collection sono li da tempo immemore, e pensare di riorganizzarle altrove mi ha sempre fatto accapponare la pelle.
Tutto perfetto, dunque, finché non mi sono trovato nella condizione di dover condividere “seriamente” le mie request con il Team, per un’effettiva collaborazione: tra i costi per la subscription e la gestione condivisa delle chiamate, che richiede – come ogni inizio – frequentissime variazioni, la mia perplessità cresceva quotidianamente…
E poi arriva Bruno (mi ricorda tanto il titolo di un film…), che con la sua semplicità architetturale cattura immediatamente la mia attenzione, spingendomi addirittura ad importare alcune collection di Postman.
In questo post, provo a riepilogare i punti di “contatto” (o, se preferite, di “attrito”) tra i due concorrenti, analizzandoli da entrambi i punti di vista per arrivare a decretare – ancorché possibile – il vincitore di questa sfida. Iniziamo!
Salvataggio delle Configurazioni
Mentre Postman salva le configurazioni di collection e request nel suo Cloud, Bruno le salva sul filesystem della macchina locale, nei suoi files “bru”. Sebbene questa possa sembrare cosa da poco, è in realtà una differenza enorme che si ripercuote pesantemente sul tema della collaborazione (di cui parleremo più avanti), dell’usabilità e della privacy.
In termini di usabilità, per modificare collection e request, oltre alla UI di Bruno, possiamo modificare direttamente i files di configurazione (i “.bru” per l’appunto) che, nella loro versione più semplice, sono simili al seguente:
Un ottimo editor che mi sento di consigliarvi (ancorché ve ne sia necessità) per l’editing dei files Bru è Visual Studio Code, per il quale (guarda il caso, alle volte) esiste l’extension denominata “Bruno” che implementa la syntax highlighting per facilitarne la gestione.
Si aggiunga che Bruno non ha un proprio Cloud (e, stando al loro Manifest, è molto probabile che non l’avrà mai) per cui la persistenza delle configurazioni è totalmente a carico dell’utente: quindi, considerando che i files di configurazione delle collection e delle request risiedono solo sul filesystem delle nostre macchine, la privacy è garantita al 100%. La loro eventuale condivisione è esclusivamente nelle nostre mani.
Collaborazione
In netta contrapposizione alla filosofia di Postman, che persiste le nostre configurazioni in qualche indefinito angolo del suo Cloud, abbiamo visto che, in Bruno, le definizioni delle request (e collection) risiedono sul nostro filesystem locale, e sono rappresentate da file di testo in formato Bru.
Quindi, se è vero che in Postman posso fare un backup esportando la mia collection, è altrettando vero che in Bruno posso facilmente trasformare la mia struttura su filesystem in un repository Git (o SVN, o Mercurial…) per pusharlo su BitBucket, GitHub o GitLab (e chi più ne ha più ne metta).
Abbiamo appena implementato la condivisione a livello di Team!!
Mentre Postman ci obbliga ad acquistare licenze per Teams composti da più di 3 Utenti (ed i prezzi non sono esattamente “popolari”), Bruno ci offre gratuitamente questa stessa possibilità “out-of-the-box”, senza alcun limite: sta a noi decidere cosa (e con chi) condividere le request. Non è meraviglioso?
Online? Offline!
Devo ammettere che non mi sono mai accorto di questo dettaglio, in quanto la mia quotidianità mi porta ad essere sempre connesso, ma- a quanto pare – Postman funziona solo in modalità “online”. Quindi, non si avvia se non ha la possibilità di contattare i suoi server (ma perché?!?!).
Al contrario, Bruno non ha alcuna necessità di connessione, in quanto tutto ciò di cui ha bisogno risiede sul filesystem locale. Questo significa che è possibile, in fase di sviluppo di un servizio, effettuare chiamate all’ambiente locale anche se siete isolati dal resto del mondo.
Questo è un altro “dettaglio” che va a consolidare ulteriormente il rispetto che Bruno ha per la nostra privacy.
Uso di Librerie Esterne
Per un Dev, l’utilizzo di librerie esterne rappresenta la normalità (la ruota ed il fuoco li hanno già inventati da tempo, non serve reinventarli) e trova un senso anche in questo contesto.
Sia Postman che Bruno offrono librerie precaricate, immediatamente fruibili, che sono in grado di coprire la maggior parte delle nostre esigenze, ad esempio:
Postman | Libreria | Bruno |
X | ajv | X |
axios | X | |
node-fetch | X | |
X | atob | X |
X | btoa | X |
X | chai | X |
X | lodash | X |
X | moment | X |
X | uuid | X |
nanoid | X | |
X | crypto-js | X |
X | cheerio | |
X | csv-parse | |
X | tv4 | |
X | xml2js | |
X | postman-collection |
Postman non sembra “strutturato” per accogliere librerie esterne nel suo ecosistema. Le alternative per farlo sono sostanzialmente due:
- Via script, scaricare la libreria da un CDN ed eseguire la funzione eval sulla stringa restituita. A seconda di dove viene posta questa chiamata, la libreria è scaricata a ogni esecuzione di request o test.
- Porre il codice sorgente della libreria in una variabile a livello di collection (o environment) e invocare una “anonymous function” per ottenere l’accesso ai suoi metodi.
Sicuramente è più facile a farsi che a dirsi ma, a parer mio, è un po’ complesso.
In Bruno le cose sono molto più semplici: la prima cosa da fare è quella di creare il file package.json con le librerie che vogliamo includere e metterlo nella root del nostro progetto:
Poi, come se fosse un qualunque progetto NodeJS, installiamo le dipendenze:
npm install
Da questo momento, le librerie sono a nostra disposizione e possiamo usarle ovunque, nell’ambito della nostra collection.
Scripting
Bruno, come Postman, offre la possibilità di customizzare le chiamate nei seguenti eventi:
- Pre-Request
- Post-Response
Ognuno di questi eventi può essere personalizzato a livello di singola request (e quindi focalizzato su una singola richiesta) oppure a livello di collection (e quindi con effetto su tutte le sottostanti richieste).
I motivi per cui si rende necessaria l’introduzione dello scripting sono i più disparati, dalla precompilazione delle variabili di una request/collection allo stacco di un JWT pre l’autenticazione, senza dimenticare l’elaborazione delle risposte ottenute dalle chiamate e chissà quante altre possibilità.
Nel contesto dello scripting, Bruno mette a disposizione tre variabili fondamentali:
- req – Rappresenta la request.
- res – Rappresenta la response.
- bru – Espone metodi che ci permettono di interagire con Bruno ed il suo ecosistema.
Nella sezione “Pre Request” possiamo andare a forzare le caratteristiche della richiesta, impostando variabili a livello di Collection o Environment se non addirittura il metodo o l’url della request.
Bruno ci permette di “nascondere” i valori dei nostri secret, ponendoli in un file “.env” salvato all’interno della nostra directory di lavoro. Per evitare che questo file venga reso pubblico dal nostro Source Control dobbiamo indicarlo nel nostro “.gitignore” (eventualmente a beneficio dei nostri collaboratori andremo a creare un file “.env.example” che conterrà valori fake per indicare ad ognuno di loro come creare il proprio file .env).
Possiamo quindi pensare di estrarre valori dai nostri secrets, generare dati randoom usando librerie esterne e, perché no, impostare valori restituiti da chiamate ad altri servizi.
Ad esempio, possiamo estrarre il segretissimo valore “MySecretValue” dal file di environment corrente per metterlo sia in un Header (X-Secret) che in una variabile:
Possiamo anche definire variabili senza passare per uno script, bensì sfruttando la UI dichiarativa:
Ciò che abbiamo appena definito può essere usato nel body della request, sfruttando la sintassi del sistema di templating di Bruno:
Dopo aver eseguito la request, possiamo verificare i parametri nel Tab “Timeline” della UI, dove possiamo avere conferma dell’Header impostato da Script (X-Secret) e del body popolato con i valori delle nostre variabili:
A questo punto, l’unico limite che possiamo porci è quello della fantasia. Ad esempio, ancora, possiamo usare le librerie precedentemente installate per generare un indirizzo e-mail (con faker) e “trasformarlo” in un colore (con uniqolor), per inviare la richiesta al nostro servizio di test:
Request Body | Response | |
=> |
Infine (spoiler della prossima sezione) possiamo verificare – tramite Assert – che il servizio ci stia restituendo lo stesso indirizzo mail che abbiamo inviato:
Assert Dichiarativi
Questa è una funzionalità che mi ha immediatamente “catturato”, in quanto ha enormemente semplificato l’implementazione dei Test più (passatemi il termine) “banali” lasciando comunque la libertà, tramite script, di implementare logiche più complesse.
Al termine di ogni request è possibile impostare dei Test, per verificarne il corretto funzionamento sulla base delle nostre assunzioni.
Mentre in Postman, per implementare i Test, siamo costretti a scrivere del codice, Bruno ci offre la possibilità di “dichiararli” alleggerendo il nostro lavoro (almeno) per quelli più semplici e lineari.
Proviamo, per esempio, a scrivere qualche test per la chiamata a api.chucknorris.io che, tipicamente, risponde con un JSON simile a questo:
Ipotizziamo di voler verificare che:
- Il campo value sia effettivamente una stringa.
- Il campo id rispetti una specifica Regular Expression.
- Lo status della response sia 200 (OK).
- Il campo update_at sia effettivamente una data/ora.
Operando nella modalità tipica di Postman avremmo scritto dei test come questi (cosa che, come possiamo constatare, possiamo fare anche in Bruno):
Tolta qualche piccola differenza sintattica, possiamo constatare che i due sistemi sono abbastanza simili. Ma Bruno ha un asso nella manica, in quanto ci permette di “dichiarare” questi test nel pannello “Assert” della nostra Request:
Notiamo che la semplicità di configurazione degli Assert mi ha permesso di controllare la validità del campo “updated_at” solamente attraverso una Regular Expression e non sfruttando la libreria moment, come è stato invece possibile fare con gli script.
Dietro le quinte, nel file Bru, i sopraccitati Assert si traducono in queste poche righe di configurazione:
Eseguire le Collection
È normale che, durante lo sviluppo di una funzionalità, si vada a testare la specifica API su cui si sta lavorando. Così come è altrettanto normale che, al termine del lavoro, si lancino tutte (o quasi) le request di una collection per verificare di non aver introdotto regressioni.
In questo contesto, il buon Postman mostra uno dei suoi limiti più odiati: ilnumero massimo di “collection run” disponibili mensilmente, ovvero:
- 25 per i piani Free/Basic
- 250 per il piano Professional
- Unlimited per il piano Enterprise
Senza entrare nel merito di queste scelte, rileviamo che Bruno non ci impone alcun limite, permettendoci un numero illimitato di esecuzioni: è sufficiente selezionare “Run” dal menu a tendina legato al nome della Collection per ottenere il risultato delle chiamate:
=> |
In alternativa alla UI, Bruno offre un runner CLI (bru), che si può installare attraverso npm:
npm install -g @usebruno/cli
da questo momento abbiamo a disposizione il nostro runner; per provarlo, apriamo un terminale e posizioniamoci nella directory principale della nostra collection. Le principali modalità di esecuzione sono le seguenti:
bru run | Esegue tutte le request della collection corrente |
bru run request.bru | Esegue una specifica request |
bru run <folder> | Esegue tutte le request di una specifica directory |
Modelli di Licensing
Le licenze software sono sempre state un tasto dolente per le aziende, poiché (spesso) vengono vissute come un costo (quasi un “pizzo” in alcuni casi) che non porta benefici effettivi se non l’arricchimento del produttore (che, comunque, non vive d’aria e d’amore).
Bruno, con la sua “Golden Edition” mette a disposizione degli Utenti alcune funzionalità in più rispetto alla Community, tra cui:
- Bru File Explorer, ovvero la possibilità di modificare una request accedendo direttamente al file Bru che la rappresenta, piuttosto che gestire eventuali script js aggiuntivi. Sono operazioni comunque possibili anche senza licenza, ma nella versione Community è necessario ricorrere a editor esterni.
- Visual Git, una UI con cui gestire in maniera visuale l’interazione con il Source Control. Personalmente sono “all’antica”, uso la cara e vecchia linea di comando… Ma per chi è avvezzo a questi strumenti visuali, si tratta di un’integrazione interessante (simile all’extension GitLens di VSCode).
- Developer Tools, una serie (ad oggi relativamente minimale) di tools per la gestione delle strutture JSON (include un “beautyfier” ed un convertitore a YAML) e dei JWT (include un decoder).
Articolo consigliato: come trovare progetti open source interessanti
Non dimentichiamo che, per Bruno, la “Licenza” è principalmente sinonimo di “supporto allo sviluppo”.
Per quanto riguarda Postman, la complessità del modello di licensing è direttamente proporzionale alla vastità dell’offerta: quattro piani (Free, Basic, Professional ed Enterprise) a prezzi mensili crescenti basati sul singolo Utente.
Il limite, a parer mio, più importante è quello relativo al numero massimo di componenti del Team che nella versione Free è fermo a 3. Per far crescere il Team anche di una sola unità è necessario passare almeno alla versione Basic, affrontando un costo non proprio “indifferente”.
Cosa manca a Bruno?
Mentre la prima commit di Bruno risale al Dicembre 2021, Postman ha visto la luce nel 2012, ben 9 anni prima! Questi anni in più gli hanno permesso di diffondersi e migliorarsi progressivamente, fino a diventare, di fatto, lo standard del settore.
Sicuramente a Bruno mancano ancora tante cose per essere davvero considerato al pari di Postman, ad esempio:
- Flows – Editor visuale di flussi di chiamate API.
- Postbot – AI applicata alla generazione di chiamate API, documentazione e test.
- Mock Servers – Permettono la simulazione di API attraverso la restituzione di dati (fake) predefiniti.
A parer mio, nonostante queste “lacune” Bruno assolve egregiamente le sue funzioni, aiutando enormemente la quotidianità del nostro lavoro di sviluppo.
La Community di Bruno è in crescita continua, il che porta a sperare per un suo roseo futuro, denso di nuove idee, features e fix, a tutto vantaggio del prodotto stesso.
Conclusioni
Non sono mai stato un sostenitore del software “perfetto”, so bene che non esiste. Invece, sono fermamente convinto che possa esistere ciò che meglio si adatta alle nostre esigenze.
Senza la pretesa di avere la verità in tasca e, soprattutto, senza la necessità di dover vendere nulla a nessuno (cosa, questa, che da tecnico, non sono proprio in grado di fare), mi permetto di consigliare a tutti voi di dare un’opportunità a Bruno. Sono certo che vi piacerà e, chissà, magari scoprirete che fa proprio al caso vostro.
Sono sinceramente curioso di ricevere i Vostri feedback: lo avete provato? Vi ha risolto qualche problema oppure no? Cosa, secondo Voi, non funziona o è migliorabile ?