Passa al contenuto principale

Remote - Client HTTP

Introduzione​

Molte volte, nelle nostre applicazioni, dobbiamo effettuare richieste HTTP verso servizi esterni. Questo può essere fatto utilizzando la risorsa _remote.

Per effettuare chiamate HTTP internamente verso altri servizi o server interni sul computer, o per chiamare qualche servizio su Internet, l'utilizzo della risorsa Remote è essenziale.

Vedi la documentazione della risorsa Remote.

Possiamo anche inviare e ricevere dati in JSON e fare upload o download di file.

Inizializzazione​

Per poter effettuare una chiamata HTTP, dobbiamo prima inizializzarla; per farlo utilizziamo il metodo init di _remote e poi memorizziamo il risultato di questa operazione in una variabile chiamata remoto, così da poter fare riferimento alla richiesta:

// Supporta l'invio di parametri HTTP
const remotoSemplice = _remote.init();
// Supporta l'invio di JSON:
const remotoJSON = _remote.init().asJSON();

Configurazione​

Possiamo anche definire configurazioni globali nell'applicazione; osserva questo esempio completo:

...
"remote": {
"esempio-basic-auth": {
"url": "https://exemplo.com/api/rest/exemplo",
"form": true,
"authorization": {
"username": "admin",
"password": "pass"
},
"data": {
"parametro1": "valore 1...",
"parametro2": "valore 2..."
}
},
"esempio-auth-token": {
"urlPrefix": "https://exemplo.com/api",
"json": true,
"authorization": "Bearer AUTH-TOKEN-QUI",
"connectTimeout": 5000,
"readTimeout": 60000,
}
},
...

Possiamo configurare un prefisso URL (urlPrefix) o l'URL completo (url).

Possiamo definire se per impostazione predefinita la richiesta deve inviare i dati come Form o JSON.

Supporta l'invio di autorizzazione di base con login e password o token.

Ed è possibile definire i dati predefiniti che saranno inviati (data), e anche i timeout di connessione (connectTimeout) e di lettura (readTimeout).

Come utilizzare​

Per utilizzare la risorsa Remote con le configurazioni definite nell'applicazione, basta inizializzare la risorsa con la chiave della configurazione, ad esempio:

const risposta = _remote.init("esempio-basic-auth").post();

E se viene definito l'URL di prefisso:

const remoto = _remote.init("esempio-auth-token");
const risposta = remoto.post(
"/services/carica-dati",
_val.map()
.set("parametro1", "valore 1")
.set("parametro2", "valore 2")
);

Richiesta HTTP​

Vedi come possiamo avviare una richiesta HTTP utilizzando la risorsa Remote.

Inviare JSON​

Per inviare dati in formato JSON dobbiamo indicare il tipo di contenuto come JSON:

Il modo semplice per farlo è utilizzare il metodo asJSON(), ad esempio:

const remoto = _remote.init().asJSON();
remoto.setURL("http://exemplo.com/salva");
const risposta = remoto.post(
_val.map()
.set("dati", "esempio")
.set("json", true)
);

Così i dati verranno inviati come JSON per i metodi HTTP POST e PUT, ma per GET e DELETE i dati vengono sempre inviati nella querystring perché per questi metodi il protocollo HTTP non supporta un corpo con dati.

Metodi HTTP​

Non dobbiamo indicare esplicitamente nell'intestazione della chiamata il suo metodo HTTP; per questo la nostra referenza della chiamata dispone di una funzione dedicata per ogni tipo di metodo HTTP:

const remoto = _remote.init();

remoto.setURL("http://exemplo.com");

remoto.get(); // per chiamate GET
remoto.post(); // per chiamate POST
remoto.put(); // per chiamate PUT
remoto.delete(); // per chiamate DELETE

Intestazione HTTP​

Per configurare i parametri dell'intestazione HTTP possiamo definire le chiavi con il metodo getHeader(), ad esempio:

const remoto = _remote.init();

remoto.getHeader().set("CHIAVE", "VALORE");

URL della richiesta​

Per indicare l'URL della richiesta basta passarlo come primo parametro delle funzioni dei rispettivi metodi HTTP:

const remoto = _remote.init().asJSON()

remoto.get("http://exemplo.com") // per chiamate GET
remoto.post("http://exemplo.com") // per chiamate POST
remoto.put("http://exemplo.com") // per chiamate PUT
remoto.delete("http://exemplo.com") // per chiamate DELETE

Aggiungere dati alla richiesta​

Se hai bisogno di aggiungere dati al corpo della richiesta, basta passarli come secondo parametro della funzione del rispettivo metodo:

const remoto = _remote.init().asJSON();

remoto.get("http://exemplo.com", _val.map().set("id_utente", 1)); // per chiamate GET
remoto.post("http://exemplo.com", _val.map().set("id_utente", 1)); // per chiamate POST
remoto.put("http://exemplo.com", _val.map().set("id_utente", 1)); // per chiamate PUT
remoto.delete("http://exemplo.com", _val.map().set("id_utente", 1)); // per chiamate DELETE

Risposta​

Dopo aver ricevuto la risposta della richiesta possiamo leggere i suoi dati utilizzando il metodo json o content:

const remoto = _remote.init().asJSON();

const risposta = remoto.post(
"http://exemplo.com",
_val.map().set("id_utente", 1)
);

if (risposta.ok()) {
_log.info("Risposta in JSON", risposta.json());
} else {
_log.info("Fallito con stato: "+ risposta.statusCode(), risposta.content());
}

Nella risposta con la funzione json() otteniamo l'array o l'oggetto fornito come Values, e con la funzione content() otteniamo contenuto in testo grezzo o l'HTML, e il numero del codice di stato ricevuto è disponibile in statusCode(), mentre ok() restituisce un valore booleano vero se il codice di stato è compreso tra 200 e 299.

Download​

Per fare download di file, o scaricare file, utilizziamo Remote con asBinary() per indicare che deve essere un trasferimento binario.

Vedi questo esempio completo di servizio:

server/services/file-download.js
const download = _remote.asBinary()
.get('https://raw.githubusercontent.com/netuno-org/platform/main/docs/images/overview.png');

if (!download.ok()) {
_log.error(`Stato download file: ${download.statusCode()}\n${download.toString()}`);
_header.status(500);
_out.json({risultato: false, errore: 'download-file-fallito'});
_exec.stop();
}

const file = download.file();
_log.info(`Nome file scaricato: ${file.name()}`);

file.save(_app.file(`storage/filesystem/server/${file.name()}`));
file.save(_storage.filesystem("server", "altro.png").file());
file.save(_os.file("/tmp/download.png"));
_out.json({risultato: true});

Il file.save viene utilizzato 3 volte intenzionalmente; per saperne di più su _app.file, _storage e _os.file, vedi il tutorial su Manipolazione di File e Cartelle.

Upload​

Per inviare un file strutturato come modulo nel formato multipart, utilizziamo asMultipartFormData().

Vedi l'esempio completo di un servizio:

server/services/file-upload.js
const file = _app.file("public/images/logo.png");

const upload = _remote.asMultipartFormData()
.post(
'http://localhost:9000/services/file-receiver',
_val.map()
.set("file", file)
);

if (upload.ok()) {
_log.info(`Caricato con successo: ${file.name()}`);
_out.json({risultato: true});
} else {
_log.error(`Stato caricamento file: ${upload.statusCode()}\n${upload.toString()}`);
_header.status(500);
_out.json({risultato: false, errore: 'caricamento-file-fallito'});
}

Nota che nell'esempio sopra il file viene inviato a un altro servizio; vedi come questo altro servizio che riceve il file può essere implementato in Netuno:

server/services/file-receiver.js
const file = _req.getFile("file");
_log.info(`Nome file ricevuto: ${file.name()}`);
file.save(_storage.filesystem("server", "ricevuto.png").file());
_out.json({risultato: true});

Conclusione​

Con la risorsa Remote possiamo integrare API esterne, esportare, importare o sincronizzare dati.

Possiamo anche integrare servizi implementati con altre tecnologie, il che permette di eseguire operazioni specifiche fornite da altri linguaggi.