In this page
Network utilities
GreyCat offers some network utilities to communicate with the outside world.
Url, Smtp and Email are part of std. The HTTP client comes from the http library.
HTTP
APIs are common ways to interact between different systems.
The HTTP client (Http, HttpRequest, HttpResponse, HttpMethod) is provided by the http library.
Declare it in your project.gcl and run greycat install to fetch it:
@library("http", "0.0.0");
The http library provides means to perform GET, POST and PUT requests.
All functions offer the possibility to specify headers.
GET
Http::get requires the HTTP endpoint as the first parameter in the form of a String. The second parameter (nullable) is a Map<String, String> of headers. This second parameter can come in handy when you need to specify a bearer token or content-type, for instance.
The body of the response is returned in the result of the function call.
fn call(myToken: String) {
var googlePage = Http::get("http://www.google.com", null);
var myData = Http::get("http://myEndpoint.lu", Map<String, String> { "Accept": "application/json", "Authorization": "Bearer ${myToken}" });
}
get_file
Http::get_file is very similar to Http::get, but rather writes the body of the response into a file instead of returning it.
There is therefore an additional parameter to specify the path of the file you want the result to be written.
It returns the HttpResponse, whose status code tells a downloaded file apart from a downloaded error page.
fn call() {
var filePath = "./data/file-${time::now().to(DurationUnit::milliseconds)}.json";
var res = Http::get_file("https://myDomain.com", filePath, null);
if (res.status_code != 200) {
throw "download failed: HTTP ${res.status_code}";
}
var content = JsonReader { path: filePath };
[...]
}
Http::getFileis deprecated. It reports no status, so a 404 writes the error page to the file and looks like a success.
POST & PUT
Http::post and Http::put have similar parameters. The first parameter is the endpoint (String), the second is the content to be sent in the body of the request, and finally the map of headers, if any.
The data is encoded in JSON.
The example shows how a Http::post request is made with params, a content, and a return value decoded from JSON into a type.
type DataFetchRequest {
sampling: Array<String>;
structure_uuids: Array<String>;
}
type DataFetchResult {
values: Array<float>;
}
fn call(base_endpoint: String, api_key: String, user_id: String, structureUuid: String) {
var endpoint = "${base_endpoint}/datafetch?api_key=${api_key}&user_id=${user_id}";
var request = DataFetchRequest {
sampling: Array<String> { "live" },
structure_uuids: Array<String> { structureUuid },
};
var result = Http<DataFetchResult>::post(endpoint, request, Map<String, String> { "Accept": "application/json" });
[...]
}
When using Http::post to issue HTTP requests to GreyCat endpoints (when communicating to a different GreyCat server, or for testing):
- if the GreyCat endpoint is exposed (
@expose), then the request can be anArray,var request = [ 123 ];, where the array elements match the endpoint parameters in order - the request can also be an object whose fields are named after the endpoint parameters
- the
Http::postwill parse the result for you and create a GreyCat value. No need to callJson::parse.
Generic Http Client
In addition to the JSON convenient methods for get, put and post, Http::send takes a full HttpRequest, where the method, the headers and the body can be configured.
The HttpResponse it returns also gives access to the status code and the response headers.
fn main() {
var req = HttpRequest {
method: HttpMethod::GET,
url: "https://echo.free.beeceptor.com?hhh=65&k=5&l",
headers: Map<String, String> { "key": "hell\"o", "Content-Type2": "application/text" },
body: "yolo\"mmm",
};
pprint(Http::send(req));
}
produces:
HttpResponse {
status_code: 200,
headers: Map<String, String> {
"alt-svc": "h3=\":443\"; ma=2592000",
"content-type": "application/json",
"vary": "Accept-Encoding",
"date": "Tue, 27 Oct 2026 09:28:17 GMT",
"access-control-allow-origin": "*",
"transfer-encoding": "chunked"
},
content: Map {
"method": "GET",
"parsedBody": Map {
"yolo\"mmm": ""
},
"protocol": "https",
"path": "/?hhh=65&k=5&l",
"headers": Map {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Type2": "application/text",
"Accept": "*/*",
"Accept-Encoding": "gzip",
"Key": "hell\"o",
"Content-Length": "8",
"User-Agent": "GreyCat/GreyCat-http/1.0",
"Host": "echo.free.beeceptor.com"
},
"parsedQueryParams": Map {
"k": "5",
"l": "",
"hhh": "65"
},
"ip": "203.0.113.42",
"host": "echo.free.beeceptor.com"
},
error_msg: null
}
HttpRequest also sets time limits (timeout, connect_timeout, idle_timeout), retries (max_attempts, retry_delay), a size limit on the response (max_response_size), request and response bodies on disk (body_file, response_file) and a Unix domain socket to connect through (unix_socket).
Http::chunked reads a streamed response, such as Server-Sent Events, as it arrives.
Typed HTTP client
Since JSON exchanges with foreign servers are hard to maintain, Http can be given a generic parameter to guide GreyCat to type the JSON response.
type ResponseTyped {
path: String?;
}
fn main() {
var req = HttpRequest {
method: HttpMethod::GET,
url: "https://echo.free.beeceptor.com?hhh=65&k=5&l",
headers: Map<String, String> { "Content-Type": "application/text" },
body: "yolo\"mmm",
};
pprint(Http<ResponseTyped>::send(req).content?.path);
}
With the typed client, the same request produces a much more compact answer:
/?hhh=65&k=5&l
The generic parameter works with all convenient methods as well: get, post, and put.
Only the body of a successful (2xx) response is decoded into the generic type, and a JSON body that does not match it throws. A successful body that is not JSON is returned as a
String. The body of a failed response is never decoded into the generic type. It is returned as text inerror_msg, andcontentisnull.
Url Utilities
It is sometimes necessary to extract parts of URLs. This utility type helps parsing and producing URLs.
var theUrl = Url::parse("https://www.mycompany.com/this/is/path?p1=true&p2=4#section");
pprint(theUrl);
Produces in the console
Url {
protocol: "https",
host: "www.mycompany.com",
port: null,
path: "/this/is/path",
user: null,
password: null,
params: Map<String, String> {
"p2": "4",
"p1": "true"
},
hash: "section"
}
The encode utility also provides a way to create “application/x-www-form-urlencoded” compatible queries.
Input can be typed objects, maps, or simply manually assembled strings.
type FormFields {
name: String;
address: String;
age: int;
}
fn main() {
var answer = FormFields{
name: "John",
address: "baker street @ london ",
age: 42
};
var encoded_form = Url::encode(answer);
pprint(encoded_form);
}
produces
name=John&address=baker%20street%20%40%20london%20&age=42
SMTP
Sending an email is possible, using the Smtp type.
SMTP Connection
You need to create an Smtp object that will specify the details of the server you target.
Once done with the configuration, you can call send with the email content you want to transmit.
fn call() {
var smtpServer = Smtp{
host: "smtp.mycompany.com",
port: 587,
mode: SmtpMode::starttls,
authenticate: SmtpAuth::login,
user: "it_s_me",
pass: "my_pass"
};
}
The Email object allows to specify the various fields of the email. Recipients, subject, content, etc.
var myEmail = Email{
from: "\"John DOE\" <john.doe@mycompany.com>",
to: ["\"John BOSS\" <john.boss@mycompany.com>"],
cc: [
"\"John LEFTBUDDY\" <john.leftbuddy@mycompany.com>",
"\"John RIGHTBUDDY\" <john.rightbuddy@mycompany.com>",
],
bcc: null,
body_is_html: false, //Text only
subject: "Important things",
body: "This is a text content.\n\nBest regards\nJohn",
};
This email can then be sent using
smtpServer.send(myEmail);