Remote - Cliente HTTP
Introdução
Muitas vezes, em nossas aplicações, precisamos fazer requisições HTTP para serviços externos. Isso pode ser feito utilizando o recurso _remote.
Para fazer chamadas HTTP internamente para outros serviços ou servidores internos no computador, ou para chamar algum serviço na internet, a utilização do recurso Remote é essencial.
Veja documentação do recurso Remote.
Inclusive podemos enviar e receber dados em JSON e fazer upload ou download de arquivos.
Inicialização
Para podermos realizar uma chamada HTTP, devemos primeiramente inicia-la, para isso utilizaremos o método init do _remote e então guardaremos o resultado desta operação em uma variável chamada remote para que assim tenhamos como referenciar a requisição:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
// Suporta enviar Parâmetros HTTP
const remoteSimples = _remote.init();
// Suporta enviar JSON:
const remoteJSON = _remote.init().asJSON();
// Suporta enviar Parâmetros HTTP
remoteSimples = _remote.init()
# Suporta enviar JSON:
remoteJSON = _remote.init().asJSON();
// Suporta enviar Parâmetros HTTP
remoteSimples = _remote.init()
# Suporta enviar JSON:
remoteJSON = _remote.init().asJSON();
// Suporta enviar Parâmetros HTTP
val remoteSimples = _remote.init()
// Suporta enviar JSON:
val remoteJSON = _remote.init().asJSON();
// Suporta enviar Parâmetros HTTP
final remoteSimples = _remote.init()
// Suporta enviar JSON:
final remoteJSON = _remote.init().asJSON();
Configuração
Também podemos definir configurações globais na aplicação, repare neste exemplo completo:
...
"remote": {
"exemplo-basic-auth": {
"url": "https://exemplo.com/api/rest/exemplo",
"form": true,
"authorization": {
"username": "admin",
"password": "pass"
},
"data": {
"param1": "valor 1...",
"param2": "valor 2..."
}
},
"exemplo-auth-token": {
"urlPrefix": "https://exemplo.com/api",
"json": true,
"authorization": "Bearer AUTH-TOKEN-AQUI",
"connectTimeout": 5000,
"readTimeout": 60000,
}
},
...
Podemos configurar um prefixo de URL (urlPrefix) ou a URL completa (url).
Podemos definir se a requisição por padrão deve enviar os dados como Form ou JSON.
Suporta enviar autorização básica com login e senha ou token.
E é possível definir os dados padrão que serão enviados (data), e ainda os tempos limites de conexão (connectTimeout) e leitura (readTimeout).
Como Usar
Para utilizar o recurso Remote com as configurações definidas na aplicação, basta iniciar o recurso com a chave da configuração, por exemplo:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const resposta = _remote.init("exemplo-basic-auth").post();
const resposta = _remote.init("exemplo-basic-auth").post();
const resposta = _remote.init("exemplo-basic-auth").post();
const resposta = _remote.init("exemplo-basic-auth").post();
const resposta = _remote.init("exemplo-basic-auth").post();
E caso seja definida a URL de prefixo:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const remote = _remote.init("exemplo-auth-token");
const resposta = remote.post(
"/services/carrega-dados",
_val.map()
.set("param1", "valor 1")
.set("param2", "valor 2")
);
const remote = _remote.init("exemplo-auth-token");
resposta = remote.post(
"/services/carrega-dados",
_val.map()
.set("param1", "valor 1")
.set("param2", "valor 2")
);
const remote = _remote.init("exemplo-auth-token");
resposta = remote.post(
"/services/carrega-dados",
_val.map()
.set("param1", "valor 1")
.set("param2", "valor 2")
);
const remote = _remote.init("exemplo-auth-token");
val resposta = remote.post(
"/services/carrega-dados",
_val.map()
.set("param1", "valor 1")
.set("param2", "valor 2")
);
const remote = _remote.init("exemplo-auth-token");
final resposta = remote.post(
"/services/carrega-dados",
_val.map()
.set("param1", "valor 1")
.set("param2", "valor 2")
);
Pedido HTTP
Veja como podemos iniciar um pedido HTTP utilizando o recurso Remote.
Enviar JSON
Para enviar dados no formato JSON precisamos sinalizar o tipo de conteúdo como JSON:
A forma simples de fazer isso é utilizando o método asJSON(), por exemplo:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const remote = _remote.init().asJSON();
remote.setURL("http://exemplo.com/salva");
const resposta = remote.post(
_val.map()
.set("dados", "exemplo")
.set("json", true)
);
const remote = _remote.init().asJSON();
remote.setURL("http://exemplo.com/salva");
resposta = remote.post(
_val.map()
.set("dados", "exemplo")
.set("json", true)
);
const remote = _remote.init().asJSON();
remote.setURL("http://exemplo.com/salva");
resposta = remote.post(
_val.map()
.set("dados", "exemplo")
.set("json", true)
);
const remote = _remote.init().asJSON();
remote.setURL("http://exemplo.com/salva");
val resposta = remote.post(
_val.map()
.set("dados", "exemplo")
.set("json", true)
);
const remote = _remote.init().asJSON();
remote.setURL("http://exemplo.com/salva");
final resposta = remote.post(
_val.map()
.set("dados", "exemplo")
.set("json", true)
);
Assim os dados vão ser enviados como JSON para os métodos HTTP de POST e de PUT, mas para GET e DELETE os dados são sempre enviados na querystring porque para estes métodos não é suportado pelo protocolo HTTP conter corpo com dados.
Métodos HTTP
Não precisamos indicar explicitamente no cabeçalho da chamada o seu método HTTP, para isso a nossa referência da chamada possui uma função própria para cada tipo de método HTTP:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const remote = _remote.init();
remote.setURL("http://exemplo.com");
remote.get(); // para chamadas GET
remote.post(); // para chamadas POST
remote.put(); // para chamadas PUT
remote.delete(); // para chamadas DELETE
const remote = _remote.init();
remote.setURL("http://exemplo.com");
remote.get() # para chamadas GET
remote.post() # para chamadas POST
remote.put() # para chamadas PUT
remote.delete() # para chamadas DELETE
const remote = _remote.init();
remote.setURL("http://exemplo.com");
remote.get() # para chamadas GET
remote.post() # para chamadas POST
remote.put() # para chamadas PUT
remote.delete() # para chamadas DELETE
const remote = _remote.init();
remote.setURL("http://exemplo.com");
remote.get() // para chamadas GET
remote.post() // para chamadas POST
remote.put() // para chamadas PUT
remote.delete() // para chamadas DELETE
const remote = _remote.init();
remote.setURL("http://exemplo.com");
remote.get() // para chamadas GET
remote.post() // para chamadas POST
remote.put() // para chamadas PUT
remote.delete() // para chamadas DELETE
Cabeçalho HTTP
Para configurar os parâmetros do cabeçalho HTTP podemos definir as chaves com o método getHeader(), por exemplo:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const remote = _remote.init();
remote.getHeader().set("CHAVE", "VALOR");
const remote = _remote.init();
remote.getHeader().set("CHAVE", "VALOR");
const remote = _remote.init();
remote.getHeader().set("CHAVE", "VALOR");
const remote = _remote.init();
remote.getHeader().set("CHAVE", "VALOR");
const remote = _remote.init();
remote.getHeader().set("CHAVE", "VALOR");
URL da Requisição
Para indicar a URL da requisição basta passar como o primeiro parâmetro das funções dos respectivos métodos HTTP:
const remote = _remote.init().asJSON()
remote.get("http://exemplo.com") // para chamadas GET
remote.post("http://exemplo.com") // para chamadas POST
remote.put("http://exemplo.com") // para chamadas PUT
remote.delete("http://exemplo.com") // para chamadas DELETE
Adicionando dados à requisição
Caso precise adicionar dados ao corpo do pedido, basta passar os mesmos como segundo parâmetro da função do respectivo método:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const remote = _remote.init().asJSON();
remote.get("http://exemplo.com", _val.map().set("user_id", 1)); // para chamadas GET
remote.post("http://exemplo.com", _val.map().set("user_id", 1)); // para chamadas POST
remote.put("http://exemplo.com", _val.map().set("user_id", 1)); // para chamadas PUT
remote.delete("http://exemplo.com", _val.map().set("user_id", 1)); // para chamadas DELETE
const remote = _remote.init().asJSON();
remote.get("http://exemplo.com", _val.map().set("user_id", 1)) # para chamadas GET
remote.post("http://exemplo.com", _val.map().set("user_id", 1)) # para chamadas POST
remote.put("http://exemplo.com", _val.map().set("user_id", 1)) # para chamadas PUT
remote.delete("http://exemplo.com", _val.map().set("user_id", 1)) # para chamadas DELETE
const remote = _remote.init().asJSON();
remote.get("http://exemplo.com", _val.map().set("user_id", 1)) # para chamadas GET
remote.post("http://exemplo.com", _val.map().set("user_id", 1)) # para chamadas POST
remote.put("http://exemplo.com", _val.map().set("user_id", 1)) # para chamadas PUT
remote.delete("http://exemplo.com", _val.map().set("user_id", 1)) # para chamadas DELETE
const remote = _remote.init().asJSON();
remote.get("http://exemplo.com", _val.map().set("user_id", 1)) // para chamadas GET
remote.post("http://exemplo.com", _val.map().set("user_id", 1)) // para chamadas POST
remote.put("http://exemplo.com", _val.map().set("user_id", 1)) // para chamadas PUT
remote.delete("http://exemplo.com", _val.map().set("user_id", 1)) // para chamadas DELETE
const remote = _remote.init().asJSON();
remote.get("http://exemplo.com", _val.map().set("user_id", 1)) // para chamadas GET
remote.post("http://exemplo.com", _val.map().set("user_id", 1)) // para chamadas POST
remote.put("http://exemplo.com", _val.map().set("user_id", 1)) // para chamadas PUT
remote.delete("http://exemplo.com", _val.map().set("user_id", 1)) // para chamadas DELETE
Resposta
Depois de receber a resposta da requisição podemos ler seus dados utilizando o método json ou content:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const remote = _remote.init().asJSON();
const resposta = remote.post(
"http://exemplo.com",
_val.map().set("user_id", 1)
);
if (resposta.ok()) {
_log.info("Resposta em JSON", resposta.json());
} else {
_log.info("Falhou com o status: "+ resposta.statusCode(), resposta.content());
}
remote = _remote.init().asJSON()
resposta = remote.post(
"http://exemplo.com",
_val.map().set("user_id", 1)
)
if resposta.ok():
_log.info("Resposta em JSON", resposta.json())
else:
_log.info(
f"Falhou com o status: {resposta.statusCode()}",
resposta.content()
)
remote = _remote.init().asJSON()
resposta = remote.post(
"http://exemplo.com",
_val.map().set("user_id", 1)
)
if resposta.ok()
_log.info("Resposta em JSON", resposta.json())
else
_log.info(
"Falhou com o status: #{resposta.statusCode()}",
resposta.content()
)
end
val remote = _remote.init().asJSON()
val resposta = remote.post(
"http://exemplo.com",
_val.map().set("user_id", 1)
)
if (resposta.ok()) {
_log.info("Resposta em JSON", resposta.json())
} else {
_log.info(
"Falhou com o status: ${resposta.statusCode()}",
resposta.content()
)
}
const remote = _remote.init().asJSON();
final resposta = remote.post(
"http://exemplo.com",
_val.map().set("user_id", 1)
);
if (resposta.ok()) {
_log.info("Resposta em JSON", resposta.json());
} else {
_log.info("Falhou com o status: "+ resposta.statusCode(), resposta.content());
}
Na resposta com a função json() obtemos o array ou o objeto fornecido como Values, e com a função content()
obtemos conteúdo em texto crú ou o HTML, e o número do código de status recebido vem no statusCode(), sendo que o ok()
retorna um valor booleano sendo verdadeiro se o código de status for dentro do intervalo de 200 e 299.
Download
Para fazer download de arquivos, ou baixar arquivos, utilizamos o remote com o asBinary() para indicar que
deve ser transferência binária.
Veja este exemplo de serviço completo:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const download = _remote.asBinary()
.get('https://raw.githubusercontent.com/netuno-org/platform/main/docs/images/overview.png');
if (!download.ok()) {
_log.error(`File download status: ${download.statusCode()}\n${download.toString()}`);
_header.status(500);
_out.json({result: false, error: 'file-download-failed'});
_exec.stop();
}
const file = download.file();
_log.info(`Downloaded file name: ${file.name()}`);
file.save(_app.file(`storage/filesystem/server/${file.name()}`));
file.save(_storage.filesystem("server", "other.png").file());
file.save(_os.file("/tmp/download.png"));
_out.json({result: true});
download = _remote.asBinary().get(
"https://raw.githubusercontent.com/netuno-org/platform/main/docs/images/overview.png"
);
if not download.ok():
_log.error(f"File download status: {download.statusCode()}\n{download.toString()}")
_header.status(500)
_out.json(_val.map().set("result", False).set("error", "file-download-failed"))
_exec.stop()
file = download.file()
_log.info(f"Downloaded file name: {file.name()}")
file.save(_app.file(f"storage/filesystem/server/{file.name()}"))
file.save(_storage.filesystem("server", "other.png").file())
file.save(_os.file("/tmp/download.png"))
_out.json(_val.map().set("result", True))
download = _remote.asBinary().get(
"https://raw.githubusercontent.com/netuno-org/platform/main/docs/images/overview.png"
);
unless download.ok()
_log.error("File download status: #{download.statusCode()}\n#{download.toString()}")
_header.status(500)
_out.json(_val.map().set("result", false).set("error", "file-download-failed"))
_exec.stop()
end
file = download.file()
_log.info("Downloaded file name: #{file.name()}")
file.save(_app.file("storage/filesystem/server/#{file.name()}"))
file.save(_storage.filesystem("server", "other.png").file())
file.save(_os.file("/tmp/download.png"))
_out.json(_val.map().set("result", true))
val download = _remote.asBinary().get(
"https://raw.githubusercontent.com/netuno-org/platform/main/docs/images/overview.png"
);
if (!download.ok()) {
_log.error("File download status: ${download.statusCode()}\n${download.toString()}")
_header.status(500)
_out.json(_val.map().set("result", false).set("error", "file-download-failed"))
_exec.stop()
}
file = download.file()
_log.info("Downloaded file name: ${file.name()}")
file.save(_app.file("storage/filesystem/server/${file.name()}"))
file.save(_storage.filesystem("server", "other.png").file())
file.save(_os.file("/tmp/download.png"))
_out.json(_val.map().set("result", true))
const download = _remote.asBinary()
.get('https://raw.githubusercontent.com/netuno-org/platform/main/docs/images/overview.png');
if (!download.ok()) {
_log.error(`File download status: ${download.statusCode()}\n${download.toString()}`);
_header.status(500);
_out.json({result: false, error: 'file-download-failed'});
_exec.stop();
}
final file = download.file();
_log.info(`Downloaded file name: ${file.name()}`);
file.save(_app.file(`storage/filesystem/server/${file.name()}`));
file.save(_storage.filesystem("server", "other.png").file());
file.save(_os.file("/tmp/download.png"));
_out.json({result: true});
O
file.saveé utilizado 3 vezes propositalmente, para saber mais sobre o_app.file,_storagee o_os.file, veja o tutorial sobre Manipulação de Arquivos e Pastas.
Upload
Para enviar um arquivo estruturado como formulário no formato multipart, utilizamos o asMultipartFormData().
Veja o exemplo completo de um serviço:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
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(`Successfully uploaded: ${file.name()}`);
_out.json({result: true});
} else {
_log.error(`File upload status: ${upload.statusCode()}\n${upload.toString()}`);
_header.status(500);
_out.json({result: false, error: 'file-upload-failed'});
}
file = _app.file("public/images/logo.png")
upload = _remote.asMultipartFormData().post(
"http://localhost:9000/services/file-receiver",
_val.map().set("file", file)
);
if upload.ok():
_log.info(f"Successfully uploaded: {file.name()}")
_out.json(_val.map().set("result", True))
else:
_log.error(f"File upload status: {upload.statusCode()}\n{upload.toString()}")
_header.status(500)
_out.json(_val.map().set("result", False).set("error", "file-upload-failed"))
file = _app.file("public/images/logo.png")
upload = _remote.asMultipartFormData().post(
"http://localhost:9000/services/file-receiver",
_val.map().set("file", file)
);
if upload.ok()
_log.info("Successfully uploaded: #{file.name()}")
_out.json(_val.map().set("result", true))
else
_log.error("File upload status: #{upload.statusCode()}\n#{upload.toString()}")
_header.status(500)
_out.json(_val.map().set("result", false).set("error", "file-upload-failed"))
end
val file = _app.file("public/images/logo.png")
val upload = _remote.asMultipartFormData().post(
"http://localhost:9000/services/file-receiver",
_val.map().set("file", file)
);
if (upload.ok()) {
_log.info("Successfully uploaded: ${file.name()}")
_out.json(_val.map().set("result", true))
} else {
_log.error("File upload status: ${upload.statusCode()}\n${upload.toString()}")
_header.status(500)
_out.json(_val.map().set("result", false).set("error", "file-upload-failed"))
}
const file = _app.file("public/images/logo.png");
final upload = _remote.asMultipartFormData()
.post(
'http://localhost:9000/services/file-receiver',
_val.map()
.set("file", file)
);
if (upload.ok()) {
_log.info(`Successfully uploaded: ${file.name()}`);
_out.json({result: true});
} else {
_log.error(`File upload status: ${upload.statusCode()}\n${upload.toString()}`);
_header.status(500);
_out.json({result: false, error: 'file-upload-failed'});
}
Repare que no exemplo acima o arquivo é enviado para outro serviço, veja como este outro serviço que recebe o arquivo pode ser implementado no Netuno:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const file = _req.getFile("file");
_log.info(`Received file name: ${file.name()}`);
file.save(_storage.filesystem("server", "received.png").file());
_out.json({result: true});
file = _req.getFile("file")
_log.info(f"Received file name: {file.name()}")
file.save(_storage.filesystem("server", "received.png").file())
_out.json(_val.map().set("result", True))
file = _req.getFile("file")
_log.info("Received file name: #{file.name()}")
file.save(_storage.filesystem("server", "received.png").file())
_out.json(_val.map().set("result", true))
val file = _req.getFile("file")
_log.info("Received file name: ${file.name()}")
file.save(_storage.filesystem("server", "received.png").file())
_out.json(_val.map().set("result", true))
const file = _req.getFile("file");
_log.info(`Received file name: ${file.name()}`);
file.save(_storage.filesystem("server", "received.png").file());
_out.json({result: true});
Conclusão
Com o recurso Remote podemos integrar APIs externas, podemos exportar, importar ou sincronizar dados.
Inclusive podemos integrar serviços implementados em outras tecnologias, o que permite realizar operações específicas fornecidas por outras linguagens.