1 HTTPClient
HTTP client is paper-thin wrapper around HttpURLConnection. It supports most HTTP communication cases when you talk to REST services and your data is JSON.
- Supports GET, POST, PUT, DELETE
- add HTTP headers (per request, per client or globally)
- convert params to x-www-form-urlencoded body or URI search params
- fluent API
- org.json support (JSONObject, JSONArray) as payload in both directions (up/down)
- wraps all Exceptions in a WebbException (a RuntimeException)
- automatically sets many boiler-plate HTTP headers (like 'Accept', 'Content-Type', 'Content-Length')
- GZip-compression for uploads (POST/PUT)
- Un-compress gzip/deflate downloads
- supports HTTPS and enables relaxing SSL-handshake (self-signed certificates, hostname verification)
- pass-through to "real" connection for special cases
- option to retry the request in case of special errors (503, 504, 'connection reset by peer')
- multi-valued parameters
- use streams as input and output (automatically closing underlying HttpURLConnection when stream is closed)
- Comfortable Basic Authentication
Return | Method | Description |
---|---|---|
HTTPClient | setSSLTrustAllFactory() | Disables server certificate verification. It's incompatible with the use of setSSLSocketFactory method. |
HTTPClient | getTrustAllCerts() | Static function returning an Array of TrustManagers (TrustManager[]) that allows to disable server certificate verification in SSL/TLS Connections |
HTTPClient | setSSLSocketFactory(String protocol, JSKeyStore ksClient, String ksClientPassword, JSKeyStore ksCACert) | Sets SSLSocket parameters: protocol: SSL or TSL ksClientJavaScript Keystore: Ax.ks.KeyStore() to obtain Client Certificate for authentication (Only first cert in keystore is used) ksClientPassword: password to open client keystore ksCACert: KeyStore with x509 Certificate to validate server certificate (Only first cert in keystore is used) |
HTTPClient | setSSLSocketFactory(String protocol, JSKeyStore ksClient, String ksClientPassword, TrustManager[] trustManagers) | This is another constructor for setSSLSocketFactory, but allows to pass result from getTrustAllCerts() as a server certificate validator. |
HTTPClient | setSSLSocketFactory(String protocol, KeyStore ksClient, String ksClientPassword, KeyStore ksCACert) | Constructor of setSSLSocketFactory allowing to pass pure Java Keystores instead of keystores opened from Javascript (Ax.ks.KeyStore()) |
HTTPClient | setSSLSocketFactory(String protocol, KeyStore ksClient, String ksClientPassword, TrustManager[] trustManagers) | Allows to pass a pure Java KeyStore as Client Certificate Keystore and an array of TrustManagers for server certificate trusting |
HTTPClient | setSSLSocketFactory(String protocol, JSKeyStore ksClient, String ksClientPassword) | This is another constructor for setSSLSocketFactory, but automatically trusts all server certificates. |
HTTPClient | setProxy() | Sets a proxy object to be used for opening the connection. |
HTTPClient | setDefaultHeader(String name, Object value) | Set the value for a named header which is valid for all requests created by this instance. |
HTTPClient | setAuthorization(String username, String password) | Set the authorization header (Basic authorization) |
HTTPClient | setBasicAuthorization(String username, String password) | Set credentials for Basic authentication |
HTTPClient | setDigestAuthorization(String username, String password) | Set credentials for Digest authentication |
HTTPClient | setBearerAuthorization(String token) | Set the Bearer authorization header token |
Request
|
get (String uri) |
Creates a GET HTTP request with the specified URI. |
Request
|
put (String uri) |
Creates a PUT HTTP request with the specified URI. |
Request
|
post (String uri) |
Creates a POST HTTP request with the specified URI. |
Request
|
delete (String uri) |
Creates a DELETE HTTP request with the specified URI. |
1.1 Request and Response
In response to get
, post
, put
or delete
operations all methods returns a Request
object. The
Request
can be configured before getting the Response
.
1.1.1 Request
Request
is a builder for an HTTP request.
Return | Method | Description |
---|---|---|
Configure request | ||
Request
|
multipleValues() | Turn on a mode where one parameter key can have multiple values. |
Request
|
param(String name, Object value) | Set (or overwrite) a parameter. The parameter will be used to create a query string for GET-requests and as the body for POST-requests with MIME-type application/x-www-form-urlencoded
|
Request
|
param(String name, Iterable values) | Set (or overwrite) a parameter with multiple values. |
Request
|
param(Map<String, Object> values) | Set (or overwrite) many parameters via a map. |
Request
|
header(String name, Object value) | Set (or overwrite) an HTTP header value. |
Request
|
body(Object value) | Set the payload for the request. Payload can be a String, a Native JSON, a JSONObject, JSONArray, byte[], File and InputStream. |
Request
|
compress() | Enable compression for uploaded data. |
Request
|
useCaches(boolean useCaches) | If true , the protocol is allowed to use caching whenever it can and it removes the automatic Cache-Control: no-cache & Pragma: no-cache headers inserted by defauit in HTTP request. |
Request
|
ifModifiedSince(long ifModifiedSince) | A nonzero value gives a time as the number of milliseconds since January 1, 1970, GMT. |
Request
|
connectTimeout(int connectTimeout) | Sets a specified timeout value, in milliseconds. |
Request
|
readTimeout(int readTimeout) | Sets the read timeout to a specified timeout, in milliseconds. |
Request
|
ensureSuccess() | By calling this method, the HTTP status code is checked and a HTTPException
is thrown if the status code is not something like 2xx |
Request
|
retry(int retryCount, boolean waitExponential) | Set the number of retries after the first request failed. When `waitExponential` is set, then there will be a exponential wait between the retries |
Execute and fetch response | ||
Response
|
asString() | Execute the request and expect the result to be convertible to String
|
Response
|
asJsonObject() | Execute the request and expect the result to be convertible to JSONObject . |
Response
|
asJsonArray() | Execute the request and expect the result to be convertible to JSONArray . |
Response
|
asBytes() | Execute the request and expect the result to be convertible to byte[] . |
Response
|
asStream() | Execute the request and expect the result to be convertible to InputStream . |
Response
|
asVoid() | Execute the request and expect no result payload (only status-code and headers). |
1.1.2 Response
Response
holds data about the response message returning from HTTP request.
Return | Method | Description |
---|---|---|
T | getBody() | Returns the payload of the response converted to the given type. |
Object | getErrorBody() | Get the body which was returned in case of error (HTTP-Code >= 400). |
int | getStatusCode() | An int representing the three digit HTTP Status-Code. |
String | getStatusLine() | The first line returned by the web-server, like "HTTP/1.1 200 OK". |
boolean | isSuccess() | Was the request successful (returning a 2xx status code)?. |
String | getResponseMessage() | Returns the text explaining the status code. |
String | getContentType() | Returns the MIME-type of the response body. |
long | getDate() | Returns the date when the request was created (server-time). |
long | getExpiration() | Returns the value of the expires header field. |
long | getLastModified() | Returns the value of the last-modified header field. |
String | getHeaderField (String name) | Returns the value of the named header field. |
1.2 HTTP Connection Examples
1.2.1 Authentication
Basic auth
Set the basic auth credentials
var result = new Ax.net.HttpClient() .setBasicAuthorization( "guest", "guest") .get("https://jigsaw.w3.org/HTTP/Basic/") .ensureSuccess() .asString(); console.log(result.getStatusCode())
200
DIGEST auth
Use Digest auth mechanism
var result = new Ax.net.HttpClient() .setDigestAuthorization( "guest", "guest") .get("https://jigsaw.w3.org/HTTP/Digest/") .ensureSuccess() .asString(); console.log(result.getStatusCode())
200
Bearer auth
Use Bearer auth mechanism
var result = new Ax.net.HttpClient() .setBearerAuthorization( "xxxxxxxxxxx") .get("yourServerIP/URL") .ensureSuccess() .asString(); console.log(result.getStatusCode())
200
1.2.2 NASA API example (HTTP Get)
The following example connects to NASA public web service API to download the picture of the day.
<script> var result = new Ax.net.HttpClient() .get("https://api.nasa.gov/planetary/apod") .param("api_key", "DEMO_KEY") .param("hd", "false") .ensureSuccess() .asJsonObject() .getBody() // Convert Java JSONObject to map to be handled by javascript! .toMap(); console.log(result); console.log(result.explanation); // Log and High resolution image URL var imageLURL = result.url; var imageHURL = result.hdurl; var image = new Ax.net.HttpClient() .get(imageLURL) .ensureSuccess() .asBytes(); var file = new Ax.io.File("/tmp/nasa.png"); var size = file.write(image.getBody()); console.log(size + " bytes written to " + file); return new Ax.sql.Blob(file); </script>
{date=2019-02-23, media_type=image, hdurl=https://apod.nasa.gov/apod/image/1902/heic1901aTriangulum.jpg, service_version=v1, explanation=Like grains of sand on a cosmic beach, stars of the Triangulum Galaxy are resolved in this sharp mosaic from the Hubble Space Telescope's Advanced Camera for Surveys (ACS). The inner region of the galaxy spanning over 17,000 light-years is covered at extreme resolution, the second largest image ever released by Hubble. At its center is the bright, densely packed galactic core surrounded by a loose array of dark dust lanes mixed with the stars in the galactic plane. Also known as M33, the face-on spiral galaxy lies 3 million light-years away in the small northern constellation Triangulum. Over 50,000 light-years in diameter, the Triangulum Galaxy is the third largest in the Local Group of galaxies after the Andromeda Galaxy (M31), and our own Milky Way. Of course, to fully appreciate the Triangulum's stars, star clusters, and bright nebulae captured in this Hubble mosaic, you'll need to use a zoom tool., title=The Stars of the Triangulum Galaxy, url=https://apod.nasa.gov/apod/image/1902/heic1901aTriangulumS.jpg}
Like grains of sand on a cosmic beach, stars of the Triangulum Galaxy are resolved in this sharp mosaic from the Hubble Space Telescope's Advanced Camera for Surveys (ACS). The inner region of the galaxy spanning over 17,000 light-years is covered at extreme resolution, the second largest image ever released by Hubble. At its center is the bright, densely packed galactic core surrounded by a loose array of dark dust lanes mixed with the stars in the galactic plane. Also known as M33, the face-on spiral galaxy lies 3 million light-years away in the small northern constellation Triangulum. Over 50,000 light-years in diameter, the Triangulum Galaxy is the third largest in the Local Group of galaxies after the Andromeda Galaxy (M31), and our own Milky Way. Of course, to fully appreciate the Triangulum's stars, star clusters, and bright nebulae captured in this Hubble mosaic, you'll need to use a zoom tool.
341728 bytes written to /tmp/nasa.png
1.2.3 Vodafone SMS Send Example (HTTP Put)
This example uses HTTP Put to emulate a SOAP Call to the Vodafone SMS Web Service.
<script> var xmlcmd = `<?xml version="1.0" standalone="no"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Header> <vodh:VODHeader xmlns:vodh="http://www.vodafone.com/soap/header/"> <vodh:commandId>ServiceDelivery</vodh:commandId> <vodh:authentication> <vodh:username>XXXX</vodh:username> <vodh:password>YYYY</vodh:password> </vodh:authentication> <vodh:service> <vodh:serviceID>31900001</vodh:serviceID> <vodh:serviceType>SMS</vodh:serviceType> </vodh:service> </vodh:VODHeader> </soapenv:Header> <soapenv:Body> <vodb:VODBody xmlns:vodb="http://www.vodafone.com/soap/body/" version="1.0"> <vodb:contextID></vodb:contextID> <vodb:destAddress>688191919</vodb:destAddress> <vodb:subServiceId>100600124168</vodb:subServiceId> <vodb:messageBody>texto de prueba</vodb:messageBody> <vodb:bodyIsText>true</vodb:bodyIsText> <vodb:deliveryReport>false</vodb:deliveryReport> <vodb:priorityFlag>0</vodb:priorityFlag> <vodb:dataCodingScheme>0</vodb:dataCodingScheme> <vodb:sourceTON>0</vodb:sourceTON> <vodb:destTON>1</vodb:destTON> <vodb:sourceNPI>0</vodb:sourceNPI> <vodb:destNPI>1</vodb:destNPI> <vodb:esmClass>0</vodb:esmClass> <vodb:protocolId>0</vodb:protocolId> </vodb:VODBody> </soapenv:Body> </soapenv:Envelope>`; var result = new Ax.net.HttpClient() .post("http://serv.cdm.vodafone.es/soap/SOAPSMS") .ensureSuccess() .body(xmlcmd) .asString() .getBody(); // Convert XML to JSON HashMap var json = new Ax.xml.XMLDocument(result).toJSON(); console.log(result); console.log(json); // Access JSON using get console.log(json.get("soapenv:Envelope").get("soapenv:Body")); </script>
1.2.4 Send invoice to Test AEAT SII Server
This example show how to emulate a raw SOAP by using HTTP Post sending an invoice SII notification to Spanish AEAT.
<script> var xml = ` <T:TicketBai xmlns:T="urn:ticketbai:emision"> <Cabecera> <IDVersionTBAI>1.2</IDVersionTBAI> </Cabecera> <Sujetos> <Emisor> <NIF>B62928809</NIF> <ApellidosNombreRazonSocial>Triathlon [GUI] S.L.</ApellidosNombreRazonSocial> </Emisor> <Destinatarios> <IDDestinatario> <NIF>B03930393</NIF> <ApellidosNombreRazonSocial>ALBIR SPORT</ApellidosNombreRazonSocial> <CodigoPostal>48200</CodigoPostal> <Direccion>Polígono Montorreta 1st. ts3 crta.Elorrio</Direccion> </IDDestinatario> </Destinatarios> <VariosDestinatarios>N</VariosDestinatarios> <EmitidaPorTercerosODestinatario>N</EmitidaPorTercerosODestinatario> </Sujetos> <Factura> <CabeceraFactura> <SerieFactura>FV</SerieFactura> <NumFactura>602</NumFactura> <FechaExpedicionFactura>22-08-2021</FechaExpedicionFactura> <HoraExpedicionFactura>02:00:00</HoraExpedicionFactura> </CabeceraFactura> <DatosFactura> <FechaOperacion>22-08-2021</FechaOperacion> <DescripcionFactura>Varios</DescripcionFactura> <DetallesFactura> <IDDetalleFactura> <DescripcionDetalle>Material auxiliar de deportes</DescripcionDetalle> <Cantidad>40.00</Cantidad> <ImporteUnitario>20.00</ImporteUnitario> <Descuento>0.00</Descuento> <ImporteTotal>800.00</ImporteTotal> </IDDetalleFactura> </DetallesFactura> <ImporteTotalFactura>15488.00</ImporteTotalFactura> <BaseImponibleACoste>0.00</BaseImponibleACoste> <Claves> <IDClave> <ClaveRegimenIvaOpTrascendencia>01</ClaveRegimenIvaOpTrascendencia> </IDClave> </Claves> </DatosFactura> <TipoDesglose> <DesgloseTipoOperacion> <Entrega> <Sujeta> <NoExenta> <DetalleNoExenta> <TipoNoExenta>S1</TipoNoExenta> <DesgloseIVA> <DetalleIVA> <BaseImponible>38400.00</BaseImponible> <TipoImpositivo>21.00</TipoImpositivo> <CuotaImpuesto>8064.00</CuotaImpuesto> <TipoRecargoEquivalencia>0.00</TipoRecargoEquivalencia> <CuotaRecargoEquivalencia>0.00</CuotaRecargoEquivalencia> </DetalleIVA> </DesgloseIVA> </DetalleNoExenta> </NoExenta> </Sujeta> </Entrega> </DesgloseTipoOperacion> </TipoDesglose> </Factura> <HuellaTBAI> <EncadenamientoFacturaAnterior> <SerieFacturaAnterior>FV</SerieFacturaAnterior> <NumFacturaAnterior>602</NumFacturaAnterior> <FechaExpedicionFacturaAnterior>22-08-2021</FechaExpedicionFacturaAnterior> <SignatureValueFirmaFacturaAnterior>Bl71zArAimKe/XtZ9Z5W3fWeYCbOz0DQplt5fX4MYD6HDuVq/jC9AKuAHsuFtcpGUui3fsFJaN0LoUGAtPZud7DafnZKD5DQ3gnY</SignatureValueFirmaFacturaAnterior> </EncadenamientoFacturaAnterior> <Software> <LicenciaTBAI>TBAIGIPRE00000000270</LicenciaTBAI> <EntidadDesarrolladora> <NIF>B62928809</NIF> </EntidadDesarrolladora> <Nombre>Axional ERP</Nombre> <Version>2021.1</Version> </Software> </HuellaTBAI> </T:TicketBai>`; const dbf = new Ax.xml.DocumentBuilderFactory(); // Firma XAdES. var signed_xml = new Ax.crypt.XAdES(dbf.parse(xml)) .setSignaturePackaging(Ax.crypt.XAdES.SIGNATUREPACKAGING.ENVELOPED) .setDigestAlgorithm("SHA512") .sign(Ax.ext.user.getKeyStoreManager('DeisterTech'), Ax.ext.user.getKeyStorePassword('DeisterTech')); // Envio a la agencia tributaria de Gipuzkoa. const keyStore =; var response = new Ax.net.HttpClient() .setSSLSocketFactory("SSL", new Ax.ks.KeyStore(Ax.ext.user.getKeyStoreManager('DeisterTech').getKeyStore()), Ax.ext.user.getKeyStorePassword('DeisterTech')) .post("https://tbai-prep.egoitza.gipuzkoa.eus/WAS/HACI/HTBRecepcionFacturasWEB/rest/recepcionFacturas/alta") .header("Content-Type", "application/xml;charset=utf-8") .ensureSuccess() .body(objMessage.message_request) .asString() .getBody(); </script>
Calling context
Method header must be as: .header("Content-Type", "application/xml;charset=utf-8").
It´s wrong if it´s written as: .header("Content-Type", "application/xml") .header("charset", "UTF-8") .header("Accept", "application/xml")
1.2.5 List Files with DropBox REST API
This example show how to list files in DropBox Folder Using REST API.
var count_nfiles = 0; var dbox_result = {}; var dbox_hasmore = true; var dbox_cursor = null; var iterations = 0; while (dbox_hasmore == true) { if (iterations++ > 100) break; if (dbox_cursor === null) { var response = new Ax.net.HttpClient() .post("https://api.dropboxapi.com/2/files/list_folder") .header("Authorization", "Bearer n2zR5tiFAAAAAAAAAAUzAzUnQsR6oPE98FN7rjb2rYP") .header("Content-Type", "application/json") .body("{\"path\": \"/Aplicaciones/Sales Layer/Definitivo\",\"limit\": 200,\"recursive\": true,\"include_media_info\": false,\"include_deleted\": false,\"include_has_explicit_shared_members\": false,\"include_mounted_folders\": true,\"include_non_downloadable_files\": true}") .asJsonObject(); } else { var response = new Ax.net.HttpClient() .post("https://api.dropboxapi.com/2/files/list_folder/continue") .header("Authorization", "Bearer n2zR5tiFAAAAAAAAAAUzAzUnQsR6oPE98FN7rjb2rY") .header("Content-Type", "application/json") .body("{\"cursor\": \"" + dbox_cursor + "\"}") .asJsonObject(); } if (response.getStatusCode() == 200) { console.log(response); console.log(response.getBody()); dbox_result = response.getBody().toMap(); dbox_cursor = dbox_result.cursor; dbox_hasmore = dbox_result.has_more == undefined ? false : dbox_result.has_more; for (var file_obj of result.entries) { count_nfiles++; console.log(file_obj.name); } console.log("TOTAL NUMBER OF FILES: " + count_nfiles); } else { console.log("Error code " + response.getStatusCode() + " body: " + response.getErrorBody()); break; } }
1.2.6 HTTP SSL Connection to unknown server
<script> var result = new Ax.net.HttpClient() .setSSLTrustAllFactory() .get("https://restcountries.eu/rest/v2/name/united") .ensureSuccess() .asString() .getBody(); console.log(result); </script>
[{"name":"United States Minor Outlying Islands","topLevelDomain":[".us"],"alpha2Code":"UM","alpha3Code":"UMI","callingCodes":[""],"capital":"","altSpellings":["UM"],"region":"Americas","subregion":"Northern America","population":300,"latlng":[],"demonym":"American","area":null,"gini":null,"timezones":["UTC-11:00","UTC-10:00","UTC+12:00"],"borders":[],"nativeName":"United States Minor Outlying Islands","numericCode":"581","currencies":[{"code":"USD","name":"United States Dollar","symbol":"$"}],"languages":[{"iso639_1":"en","iso639_2":"eng","name":"English","nativeName":"English"}],"translations":{"de":"Kleinere Inselbesitzungen der Vereinigten Staaten","es":"Islas Ultramarinas Menores de Estados Unidos","fr":"Îles mineures éloignées des États-Unis","ja":"合衆国領有小離島","it":"Isole minori esterne degli Stati Uniti d'America","br":"Ilhas Menores Distantes dos Estados Unidos","pt":"Ilhas Menores Distantes dos Estados Unidos","nl":"Kleine afgelegen eilanden van de Verenigde Staten","hr":"Mali udaljeni otoci SAD-a","fa":"جزایر کوچک حاشیهای ایالات متحده آمریکا"},"flag":"https://restcountries.eu/data/umi.svg","regionalBlocs":[],"cioc":""},{"name":"Tanzania, United Republic of","topLevelDomain":[".tz"],"alpha2Code":"TZ","alpha3Code":"TZA","callingCodes":["255"],"capital":"Dodoma","altSpellings":["TZ","United Republic of Tanzania","Jamhuri ya Muungano wa Tanzania"],"region":"Africa","subregion":"Eastern Africa","population":55155000,"latlng":[-6.0,35.0],"demonym":"Tanzanian","area":945087.0,"gini":37.6,"timezones":["UTC+03:00"],"borders":["BDI","COD","KEN","MWI","MOZ","RWA","UGA","ZMB"],"nativeName":"Tanzania","numericCode":"834","currencies":[{"code":"TZS","name":"Tanzanian shilling","symbol":"Sh"}],"languages":[{"iso639_1":"sw","iso639_2":"swa","name":"Swahili","nativeName":"Kiswahili"},{"iso639_1":"en","iso639_2":"eng","name":"English","nativeName":"English"}],"translations":{"de":"Tansania","es":"Tanzania","fr":"Tanzanie","ja":"タンザニア","it":"Tanzania","br":"Tanzânia","pt":"Tanzânia","nl":"Tanzania","hr":"Tanzanija","fa":"تانزانیا"},"flag":"https://restcountries.eu/data/tza.svg","regionalBlocs":[{"acronym":"AU","name":"African Union","otherAcronyms":[],"otherNames":["الاتحاد الأفريقي","Union africaine","União Africana","Unión Africana","Umoja wa Afrika"]}],"cioc":"TAN"},{"name":"United Arab Emirates","topLevelDomain":[".ae"],"alpha2Code":"AE","alpha3Code":"ARE","callingCodes":["971"],"capital":"Abu Dhabi","altSpellings":["AE","UAE"],"region":"Asia","subregion":"Western Asia","population":9856000,"latlng":[24.0,54.0],"demonym":"Emirati","area":83600.0,"gini":null,"timezones":["UTC+04"],"borders":["OMN","SAU"],"nativeName":"دولة الإمارات العربية المتحدة","numericCode":"784","currencies":[{"code":"AED","name":"United Arab Emirates dirham","symbol":"د.إ"}],"languages":[{"iso639_1":"ar","iso639_2":"ara","name":"Arabic","nativeName":"العربية"}],"translations":{"de":"Vereinigte Arabische Emirate","es":"Emiratos Árabes Unidos","fr":"Émirats arabes unis","ja":"アラブ首長国連邦","it":"Emirati Arabi Uniti","br":"Emirados árabes Unidos","pt":"Emirados árabes Unidos","nl":"Verenigde Arabische Emiraten","hr":"Ujedinjeni Arapski Emirati","fa":"امارات متحده عربی"},"flag":"https://restcountries.eu/data/are.svg","regionalBlocs":[{"acronym":"AL","name":"Arab League","otherAcronyms":[],"otherNames":["جامعة الدول العربية","Jāmiʻat ad-Duwal al-ʻArabīyah","League of Arab States"]}],"cioc":"UAE"},{"name":"United Kingdom of Great Britain and Northern Ireland","topLevelDomain":[".uk"],"alpha2Code":"GB","alpha3Code":"GBR","callingCodes":["44"],"capital":"London","altSpellings":["GB","UK","Great Britain"],"region":"Europe","subregion":"Northern Europe","population":65110000,"latlng":[54.0,-2.0],"demonym":"British","area":242900.0,"gini":34.0,"timezones":["UTC-08:00","UTC-05:00","UTC-04:00","UTC-03:00","UTC-02:00","UTC","UTC+01:00","UTC+02:00","UTC+06:00"],"borders":["IRL"],"nativeName":"United Kingdom","numericCode":"826","currencies":[{"code":"GBP","name":"British pound","symbol":"£"}],"languages":[{"iso639_1":"en","iso639_2":"eng","name":"English","nativeName":"English"}],"translations":{"de":"Vereinigtes Königreich","es":"Reino Unido","fr":"Royaume-Uni","ja":"イギリス","it":"Regno Unito","br":"Reino Unido","pt":"Reino Unido","nl":"Verenigd Koninkrijk","hr":"Ujedinjeno Kraljevstvo","fa":"بریتانیای کبیر و ایرلند شمالی"},"flag":"https://restcountries.eu/data/gbr.svg","regionalBlocs":[{"acronym":"EU","name":"European Union","otherAcronyms":[],"otherNames":[]}],"cioc":"GBR"},{"name":"United States of America","topLevelDomain":[".us"],"alpha2Code":"US","alpha3Code":"USA","callingCodes":["1"],"capital":"Washington, D.C.","altSpellings":["US","USA","United States of America"],"region":"Americas","subregion":"Northern America","population":323947000,"latlng":[38.0,-97.0],"demonym":"American","area":9629091.0,"gini":48.0,"timezones":["UTC-12:00","UTC-11:00","UTC-10:00","UTC-09:00","UTC-08:00","UTC-07:00","UTC-06:00","UTC-05:00","UTC-04:00","UTC+10:00","UTC+12:00"],"borders":["CAN","MEX"],"nativeName":"United States","numericCode":"840","currencies":[{"code":"USD","name":"United States dollar","symbol":"$"}],"languages":[{"iso639_1":"en","iso639_2":"eng","name":"English","nativeName":"English"}],"translations":{"de":"Vereinigte Staaten von Amerika","es":"Estados Unidos","fr":"États-Unis","ja":"アメリカ合衆国","it":"Stati Uniti D'America","br":"Estados Unidos","pt":"Estados Unidos","nl":"Verenigde Staten","hr":"Sjedinjene Američke Države","fa":"ایالات متحده آمریکا"},"flag":"https://restcountries.eu/data/usa.svg","regionalBlocs":[{"acronym":"NAFTA","name":"North American Free Trade Agreement","otherAcronyms":[],"otherNames":["Tratado de Libre Comercio de América del Norte","Accord de Libre-échange Nord-Américain"]}],"cioc":"USA"},{"name":"Mexico","topLevelDomain":[".mx"],"alpha2Code":"MX","alpha3Code":"MEX","callingCodes":["52"],"capital":"Mexico City","altSpellings":["MX","Mexicanos","United Mexican States","Estados Unidos Mexicanos"],"region":"Americas","subregion":"Central America","population":122273473,"latlng":[23.0,-102.0],"demonym":"Mexican","area":1964375.0,"gini":47.0,"timezones":["UTC-08:00","UTC-07:00","UTC-06:00"],"borders":["BLZ","GTM","USA"],"nativeName":"México","numericCode":"484","currencies":[{"code":"MXN","name":"Mexican peso","symbol":"$"}],"languages":[{"iso639_1":"es","iso639_2":"spa","name":"Spanish","nativeName":"Español"}],"translations":{"de":"Mexiko","es":"México","fr":"Mexique","ja":"メキシコ","it":"Messico","br":"México","pt":"México","nl":"Mexico","hr":"Meksiko","fa":"مکزیک"},"flag":"https://restcountries.eu/data/mex.svg","regionalBlocs":[{"acronym":"PA","name":"Pacific Alliance","otherAcronyms":[],"otherNames":["Alianza del Pacífico"]},{"acronym":"NAFTA","name":"North American Free Trade Agreement","otherAcronyms":[],"otherNames":["Tratado de Libre Comercio de América del Norte","Accord de Libre-échange Nord-Américain"]}],"cioc":"MEX"}]
Calling setSSLTrustAllFactory is equivalent to create a TrustAllCerts KeyStore and pass it to setSSLSocketFactory
.setSSLTrustAllFactory() // is equivalent to: var kst = Ax.net.HttpClient.getTrustAllCerts(); .setSSLSocketFactory("SSL", null, null, kst)
1.2.7 HTTP SSL Post with Client Certificate Auth
HTTP Client allows to use a certificate keystore to client authentication in server.
Beaware only first certificate in keystore is used.
<script> // Open certificate from disktool storage var cert_bytes = Ax.util.Base64.decode('MIIKtQIBAzCCCm4GCSqGSIb3DQEHAaCCCl8EggpbMIIKVzCCBXsGCSqGSIb3DQEHAaCCBWwEggVoMIIFZDCCBWAGCyqGSIb3DQEMCgECoIIE+zCCBPcwKQYKKoZIhvcNAQwBAzAbBBRm76OaYEHK5WdX7u9wwKMs/Frg1QIDAMNQBIIEyKaSSDalleIKZwxXnp857fMMboiZUTDAnOb3qLSUrN1sznDKDXSrZCRuuLs+riWAeAo5Q+UVPyVMjslwaW8AtZYKf5sA5W5w3d1z5dM2ezB06PVo7dn6Qv2H9zuFDZCeFMGbe9CDrO6vEFdG6SUvltzn/A9vN3DUBE+fyFUdwZssSswOU7/DtPpSb6DznyWxTPIuBM60a5dmM36OS7a2m9ACxxIgzOGRjH2RZa2EV3Xh9BgwmEQa0WIQd/i7C4T0Ahe9Se8r0Y5XjK8DKNWY2Io52iAX838eSpoN2LX8RVRsPTuCqyt5KD1aSkTfpvAFIlPFMrwnVVGJEfMkdipZHI91bPNJYZ0TwYeck2iJqOWNSdmSAjEKs/kBQ8eaAqF+aBacJDy8Uzk9IDIZUPsxFAhWn4S3yrETmftx7yWmDSIlIM5vQzCSsoUM4x6zilQw1AzugAFV6M43RrumjmwmqhP2fxGVAOWb0NFoOtGusA5vDqNzKx9rt1fkaMK0qpt3x6c84t7Wfm0BrIJCHDU+bGK1lGU1ZXgkWbJgrRIsbWjFDJ3CorJXtu5zCmBwwrLMua2Oi1nkiEH5OLTExhl1DdnxMIpSBb0gSR3jxaOI6IqFKz9sGudduRrc//CjLTcHf4JLQXUZZbSKfpsp27jfSJU7Mc8HAM7H7yPXI11wzG4J7wpxGnD8uHecO1GRt4wtCY4bXQlFCOVBjU8srp1iFxqgZUzhD53nqTrW7pJOm9+ZeyGu1J3z46D7b2UO1ZA0cRubCTAQ/cU200P6rRfxIzoO4Dw0HKFkn9YfyK6BmjimPLsh32m6hpBZHBEQL7K3VHeRnPdgU10s5aWI62WI3FvQq4lcpwCb0e5pgJJ0gtz3G+X2+HAQwJp/1o2dlsXLgXoCFvyLDBwNI14MNz/PcGo/09I5BWp/EEiS9jUJZiNBxi2f7gV4D35dZgtXMRKWHxcehFm41IfCtmZILmXeV3YSYQd8x5i5xZia6sZdhQhPHu8UaTaCYogMMwfW4bIHiw4do+gS5UoIEOOo205tS1XvSPH/c3RDsQe7EGBXEwsKrPUbdz9YBItCkv+As5iQ1Cc9+A9bnUU5O6KcztkVCu6dMNqVWp1mSqxzIVlcjo7kNBqQSBjYoDpUrS//aIgE3d1ZDWN/pSSp9op1MA7uGZYxEYXI4oAVu/X2k6ezddxgu+ZUup/T6a+JyEWdFMr/D+U/+Nz27nOg9ufD0wQB7y88u7+yHaJ0FP77ReCL6U8PHkpxVd6AqypHuIUCjZMVaZFBvEPmtaRjsZr211Srhk9AfMuYTAV57XKKeIObTJcC6uHgwat7w3zF3DS0eZqtxKMQndY4lfssDAktoGSY0VNrKSusgf+xJAbIxRnoMxas8z/I0wCnj+uYmLj1wwwAuyLLTm+1CoyGab6BtuGQmAE2XfLiWn/e/rES6GwWyM7iSQSGd+60ppcjSBabl7FDN+7ji6+tHL00cc7wVWnhaS+zQTCj8Nn1tJ57srNpANfoxJ40nO1gyfqSXXj7U27QSj1sX8tzfTDUyR8QqCHjY+5/AFEQyNo9rl3jeyy2YqiuRN7YZ1NnHNNTJ/BrkFwlk65brTZfbWAwJG2h9tnEy18CjneSzGTAlTFSMC0GCSqGSIb3DQEJFDEgHh4ANwB1AHMAZABpAHMAMQAxADMAMAAxADkANQA0ADEwIQYJKoZIhvcNAQkVMRQEElRpbWUgMTU0OTY0OTgxNDUzMTCCBNQGCSqGSIb3DQEHBqCCBMUwggTBAgEAMIIEugYJKoZIhvcNAQcBMCkGCiqGSIb3DQEMAQYwGwQUwjP8gytj5i6ymDhZDDFdUd27/bgCAwDDUICCBID1Ay3ha54e4ur5z6ZaASpqQKgie6fMz+kxs6iTP6TOkH6hYW3oNz92oPaseuGmeUVd9YlevbDfrCb571y0uCEnQtj0Umehe9agCUcfgZPN1xkIT+a6vO4A4XY1ETjL+shSaGzRTcv6z3+PpN5BVuRmNifgX0AyvzZPz1jZTloMxO4iHUvOWUAULVXm2lTAUAHwPa/wf1GIrNPR5oKBtMCeWm4uFg0+Tsbvu4MauFf6YEWu9Ifdm9wYP/QRFQHdQUuzxRrbJ01S3eN9uP44K2SOq51bDRUibiwaL1XolV2QIaeCxsVA9NeSipynaa9v/EkOwBrTsKiJ+euK3yId/iFjphSpQGZzqjzfjgYmPznxbRssz//Dw7H19EDR8g03/hKdcwvPIgggXPEs+13Z982Gdi1U7kAq7iokOpBsK007Ti9tWQMCX1yibYBweglVaQMeDwPzEeE/DpjFrWBAGcG4Ah2Xe78tV+CPPLNjpPHt+UM2W/HBmKltdx/cfLmBbYs+x+4wLWSiqCMpgpLv+ESm2CGlasrtWhtB4WVA8HQVPnM0J131gzHUt8v5ZRdxpcweKoVvAJlyqgJGT5IeXuya6Ohs0u/nOIQTi0voVkGxQhXk/+aZnQJlhonJu4GPejXVx4Hr1h/ms0opPOtFErXBBGL427gJrPAHvsZf50doJH4tT0GlicgwYokKZnatC0tiobxD7I6+lpR3jGzbnbmMt4tImU0WqtisrxRmpjx7lE+P+AUBtenhq8j3Jia1uy7qF8NY6FHlnXDwRXjN9TIDuR/FqNPyddyrwm11JR7rQ8N6zRfQuo5kdUwtS/OmjgTACKWeGIiBS1YjbgdlyUkFFktqmxmnsJ2XBxLOGcU1iWru0UezrO20A7snPLqJYAXGLPbBJ4G4D3iek7uZvQUz5ffBnhyGGcZXGIUW6B4cYhZHo90vQIWawfkK6ftRuQPv7hMGIKLIHvy5gWSe5Ifb3LjZywGmqYtiawFR9iKOZNXU0zc3dfxYlUZENElESNEkeX4LHf2vUyq5QZ4B7o65IrGbIXyovdEpxxLjjznJefed71ELjXai+Y8f2tkd5HhuWHHZ3qARVAeBDupBYWag8/HrUm/fTwfd8mEpSV7C8v2zga6jn/3NkOG+BrKZzJ2VS5tfnZjAr031z67g4ke0W/ucpt1W/9nTrJrAEaleU4KGU+LkEnqAtFvVAvjU0EFE1GafCOvQlIkWx191qlwO9SU4Hi22rY3quwuB3MVHstJ2iidd06jOCU8CijaqxGRJTBA5qyV9wcANfH40AUiiVgPqsmX09nYWZhTqnpWNICMNnBQOciFoINo6VjSc32XuWL+mPkTnzsETcxztOZOa5ILhlJpeUhYy7qoboaPoWXqDiVHXboWF+MSiioWc/37ECqgXsc3XYmkKo4eON54jjPE1zFWFmSOZsQ9pjbml3YubbKLfUJ0iCOvgu6AO3lv8KDj8bfggq69Wqc1OUTfbHiKUXGsf8MpG+5DRC70WLPVrhu2G+Zh2Rw+EvalF14UwPjAhMAkGBSsOAwIaBQAEFILA0ZHxz5tgRwgty11IIZLXsaCvBBQKuiczp2SSLg6HYZmsmLU91QzCrAIDAYag'); // Also you can open direct file // var cert_bytes = new Ax.io.File('7USDIS113019541.p12'); // Open Client Certificate Keystore from file var ksc = new Ax.ks.KeyStore('pkcs12').load(cert_bytes, 'TBrA7MqN'); // Get Trust All Certificate from Servers var kst = Ax.net.HttpClient.getTrustAllCerts(); // Also, we can use a KeyStore to store trusted server certificates // var kst = new Ax.ks.KeyStore().load(new Ax.io.File('myCAStore.jks'), 'capass'); var xmlmsg = ` <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:urn="urn:wsdltypes.nmvs.eu:v3.0" xmlns:urn1="urn:types.nmvs.eu:v3.0"> <soap:Header/> <soap:Body> <urn:SupportPingRequest> <urn1:Input>Hello World!</urn1:Input> </urn:SupportPingRequest> </soap:Body> </soap:Envelope> `; // Create Http Client Connection // Define SSL Socket Parameters(SSLContext Instance as SSL, ksc =Certificate to Client authentication, Password of certificate, KeyStore for trusted server certificates) var result = new Ax.net.HttpClient() .setSSLSocketFactory("SSL", ksc, 'TBrA7MqN', kst) .post("https://ws-support-prod-es.nmvs.eu:8448/WS_SUPPORT_V1/SupportServiceV30") .body(xmlmsg) .ensureSuccess() .asString() .getBody(); // Convert XML to JSON HashMap var json = new Ax.xml.XMLDocument(result).toJSON(); // Access JSON using get console.log(json.get("soap:Envelope").get("soap:Body")); </script>
1.2.8 Using Google Directions API
<script> </script>
1.2.9 Reading Stock Quotes
The following example connects to quandl
stock service and retrieves a CSV for FaceBook stock data.
This could be acomplised by using only Ax.rs.Reader
but in a more complex example you may
need HTTP client control (for example, user authentication to access to URL).
<script> var result = new Ax.net.HttpClient() .get("https://www.quandl.com/api/v3/datasets/WIKI/FB/data.csv") .ensureSuccess() .asString() .getBody(); // Read CSV string into ResultSet var rs = new Ax.rs.Reader().csv(options => { options.setString(result); }); return rs; </script>
+----------+-------+-------+-------+-------+-------------+-----------+-----+-------+-------+-------+-------+-------------+
|Date |Open |High |Low |Close |Volume |Ex-Dividend|Split|Adj. Op|Adj. Hi|Adj. Lo|Adj. Cl|Adj. Volume |
| | | | | | | |Ratio|en |gh |w |ose | |
+----------+-------+-------+-------+-------+-------------+-----------+-----+-------+-------+-------+-------+-------------+
|2018-03-27|156.310|162.850|150.750|152.190| 76787884.000| 0.000|1.000|156.310|162.850|150.750|152.190| 76787884.000|
|2018-03-26|160.820|161.100|149.020|160.060|125438294.000| 0.000|1.000|160.820|161.100|149.020|160.060|125438294.000|
|2018-03-23|165.440|167.100|159.020|159.390| 52306891.000| 0.000|1.000|165.440|167.100|159.020|159.390| 52306891.000|
|2018-03-22|166.130|170.270|163.720|164.890| 73389988.000| 0.000|1.000|166.130|170.270|163.720|164.890| 73389988.000|
...
2 HttpRequest
The class HttpRequest is automatically declared as Ax.request
and it's available from script context
providing information about current HttpServletRequest that has stated the script execution.
You can access most HttpServletRequest methods from JavaScript
<script> console.log(" Method:" + Ax.request.getMethod()); console.log(" Headers:" + Ax.request.getHeaderNames()); console.log("Parameters:" + Ax.request.getParameterNames()); console.log("Attributes:" + Ax.request.getAttributeNames()); console.log(" Parts:" + Ax.request.getParts()); console.log(" URI:" + Ax.request.getRequestURI()); console.log(Ax.request.dump()); switch(Ax.request.getHeader("content-type")) { case "text/plain": console.log("is text"); break; case "text/xml": console.log("is xml"); break; default: console.log("is not supported"); break; } </script>
Method:GET
Headers:[content-size, content-type]
Parameters:[]
Attributes:[]
Parts:null
URI:null
<request class='deister.axional.server.script.lib.httpservlet.StaticHttpServletRequest' from='js'>
protocol : null
remoteAddr : 127.0.0.1
remoteHost : localhost
scheme : http
secure : false
serverName : null
serverPort : 0
method : GET
pathInfo : null
pathTranslated : null
queryString : null
remoteUser : null
requestedSessionId : null
requestedSessionIdFromCookie : false
requestedSessionIdFromURL : false
requestedSessionIdValid : false
requestURI : null
servletPath : null
userPrincipal : null
<headers>
content-size : 92
content-type : text/xml
</headers>
<parameters
</parameters>
<attributes
</attributes>
</request>
2.1 Multipart Requests (aka File upload)
Multipart requests combine one or more sets of data into a single body, separated by boundaries. You typically use these requests for file uploads and for transferring data of several types in a single request. File uploads typically use the multipart/form-data media type.
To build a multipart form data entity, we use the class Ax.net.util.MultiPartEntityBuilder
to add each 'part'. For instance:
let part1 = new Ax.io.File("/tmp/file1.pdf"); part1.write("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"); let part2 = new Ax.io.File("/tmp/file2.pdf"); part2.write(` Doubt thou the stars are fire; Doubt that the sun doth move; Doubt truth to be a liar; But never doubt I love. `); // our multipart form data entity builder let builder = new Ax.net.util.MultiPartEntityBuilder(); builder.addFieldPart("lorem_ipsum", part1, "text/plain"); builder.addFieldPart("hamlet", part2, "text/plain"); console.log(new Ax.lang.String(builder.build())) var response = new Ax.net.HttpClient() .post("http://localhost:8090/service/rest/junit_studio/test/v1/api/file_upload") .header("Content-Type", "multipart/form-data;boundary=" + builder.getBoundary()) // IMPORTANT!!! .header("Authorization", "Bearer " + Ax.ext.user.getJsonWebToken()) .body(builder.build()). asString(); ; console.log("getStatusCode",response.getStatusCode()); console.log("post_message",response.getBody()); console.log("headers",response.getHeaderFields()); console.log("body",response.getBody());
3 HttpResponseBuilder
A class used to build Response instances that contain metadata instead of or in addition to an entity. Instance methods provide the ability to set metadata such as http status code, http headers, http response type and cache control
let data = { name :"John", familyName : "Doe"} return new Ax.net.HttpResponseBuilder() .status(201) .entity(data) .header("X-test", "1234") .type("application/json") .cacheControl("public", 3600) .build();
// redirect return new Ax.net.HttpResponseBuilder() .seeOther("/api/junit_studio/v1/test/response/wrapper") .build();
Calling context
Ax.net.HttpResponseBuilder should only be called when the result of a JS Script execution is used as the response of an HTTP call. (E.g. In Js Scripts called by the REST API wrapper)
4 JSContainerRequestContext
Exposes a ContainerRequestContext to JS. A ContainerRequestContext is a mutable class that provides request-specific information for the filter, such as request URI, message headers, message entity or request-scoped properties. The exposed setters allow modification of the exposed request-specific information.
Calling context
JSContainerRequestContext is not exposed via Ax
namespace. An instance of this class is passed as a parameter in REST api function filters.
Add a header
function restApiFilterFunction(context) { // add a header context.getHeaders().add("x-myheader", "value"); // context.abortWith(new Ax.net.HttpResponseBuilder() .seeOther("/api/junit_studio/v1/test/response/wrapper").build() ) }
Abort request and redirect
function restApiFilterFunction(context) { // context.abortWith(new Ax.net.HttpResponseBuilder() .seeOther("/api/junit_studio/v1/test/response/wrapper").build() ) }
5 Testing HTTP
Some times we need to debug (or compare) a request send to an http server. A simple way is to setup a linux echo http server that can be used to log (echo) an http request.
You can use the following code to compile an http echo server in Java.
compile and run
$ javac server.java $ java server
Echo server Java source code
import java.net.*; import java.io.*; public class server { public static void main(String[] argv) throws IOException { // Only local interface // String host = "127.0.0.1"; // All server interfaces String host = "0.0.0.0"; short port = 8080; if(argv.length >= 2) host = argv[1]; if(argv.length >= 1) port = Short.parseShort(argv[0]); ServerSocket server = null; try { server = new ServerSocket(port, 0, InetAddress.getByName(host)); System.err.println("Server listening on " + host + ":" + port + "\n"); int read; byte[] buffer = new byte[8192]; while(true) { Socket client = server.accept(); System.out.println("Connection accepted from " + client.getRemoteSocketAddress()); PrintWriter out = new PrintWriter(client.getOutputStream(), true); InputStream in = client.getInputStream(); while((read = in.read(buffer)) > 0) { System.out.write(buffer, 0, read); } System.out.println(""); out.write("HTTP/1.1 200 OK"); out.close(); in.close(); client.close(); } } finally { System.out.println("Closing"); if(server != null) server.close(); } } }