Jarvis
Repository | https://github.com/dyalog/Jarvis |
Copyright | Made with Material for MkDocs. Contents copyright ©2015-2024 Dyalog, LTD |
Note
This documentation continues to be a work in progress. General usage and settings references are complete. Frequent updates will be forthcoming as additional sections are completed.
Jarvis is an HTTP server that makes it easy to create a web service to provide access to your APL code from the web or a local network.
Any client program written in any language on any platform that can process HTTP requests can access a Jarvis-based web service. This vastly increases the potential audience for your application - the client can be a standard web browser, a phone app, a browser-based app, or a custom client written in a language like Python or C# and yes, even APL.
Introduction
The name Jarvis is a pseudo-acronym for JSON and REST Service ("vice" becomes "vis") and was also inspired by J.A.R.V.I.S. (Just A Rather Very Intelligent System) from the Marvel Cinematic Universe.
Formatting Note: You may notice that the name "Jarvis" is formatted in two, possibly three, different ways:
- Jarvis refers Jarvis as an abstract idea
Jarvis
refers to the Dyalog APL Jarvis class- Jarvis (unadorned) is probably the author's mistake for not having formatted the occurrence as one of the above.
Design Goals
Jarvis is designed to make it very easy for an APLer to create web services without requiring in-depth knowledge of web service frameworks. In designing Jarvis we've attempted to
- Make Jarvis' default behavior simple and applicable to many use cases
- Make few assumptions about what the user actually needs to do
- Provide hooks to allow the user to tailor or extend Jarvis' behavior if needed
Create an APL Web Service in 5 Minutes
If you know how to write a monadic, result-returning APL function, you're ready to run your first Jarvis-based web service. Here's how:
-
If you already have a copy of the
Jarvis
class, skip to step 3. Otherwise, load theHttpCommand
utility so that we can download a copy of Jarvis and also useHttpCommand
for testing our web service.]load HttpCommand
-
Next, download a copy of Jarvis. Note, the following statement downloads the latest, perhaps pre-release, version of the Jarvis class for this quick demonstration. For a production environment, you should use a released version of Jarvis.
HttpCommand.Fix
both downloads and runs⎕FIX
on an APL code file from the web.HttpCommand.Fix 'https://raw.githubusercontent.com/Dyalog/Jarvis/master/Source/Jarvis.dyalog'
-
Write one or more monadic, result-returning APL functions. For instance:
)cs # sum ← {+/⍵} ⍝ dfns work total ← +/ ⍝ derived functions work ⎕FX '∇r←addemup a' 'r←+/a' '∇' ⍝ and of course, tradfns work
-
Next, create an instance of
Jarvis
usingJarvis.New
.
j←Jarvis.New ''
Jarvis
instance with all settings set to their default values. By default, Jarvis
will use port 8080 and look for your endpoint code in #
.
- You can now run your web service running on port 8080 and serving code from the # (root) namespace.
(rc msg)←j.Start 2024-09-06 @ 15.46.24.199 - Starting Jarvis 1.18.1 2024-09-06 @ 15.46.24.217 - Conga copied from C:\Program Files\Dyalog\Dyalog APL-64 19.0 Unicode/ws/conga 2024-09-06 @ 15.46.24.221 - Local Conga v3.5 reference is #.Jarvis.[LIB] 2024-09-06 @ 15.46.24.231 - Jarvis starting in "JSON" mode on port 8080 2024-09-06 @ 15.46.24.232 - Serving code in # 2024-09-06 @ 15.46.24.237 - Click http://192.168.001.123:8080 to access web interface
If the server started successfully, you'll see messages similar to those above displayed to the APL session and the return code rc
should be 0
and msg
should be empty. If there was any problem starting Jarvis
, rc
will be non-0
and msg
will contain a (hopefully) helpful message about the problem that occurred.
Now, let's test our service using Jarvis' built-in HTML interface. You could click on the link displayed or open your favorite browser to http://localhost:8080, but just for fun, we'll use Dyalog's HTMLRenderer object.
'h' ⎕WC 'HTMLRenderer' ('URL' 'localhost:8080')
We select the Endpoint (APL function) we want from the drop down list, enter some valid JSON data ([1,3,5]
), and press Send to send the request to Jarvis. Jarvis' response is then sent back and displayed.
We can also use HttpCommand
to call the web service.
(url data headers)←'localhost:8080/total' '[1,3,5]' ('content-type' 'application/json')
(HttpCommand.Do 'POST' url data headers).Data
9
We can use the cURL command to call the web service.
C:\> curl -H "content-type: application/json" -X POST -d [1,3,5] http://localhost:8080/addemup
9
To stop the service, simply type j.Stop
Interested? Read on...
Usage ↵
Conceptual Overview
Jarvis is implemented as a Dyalog APL class. It's okay if you're not familiar with the object oriented features of Dyalog. All you really need to understand is that a Jarvis server is an "instance" of the Jarvis
class. You create an instance of the class and then configure and run the instance. This is covered in Using Jarvis.
Terminology
Jarvis supports two different "paradigms" which define how the client will interact witht the Jarvis service. This section defines some terms that we will use in the discussion below about Jarvis paradigms.
Client
This is the component sending a request to the Jarvis service and receiving Jarvis' response. The client can be anything that can send HTTP requests and receive HTTP responses. It could be a web browser, a program, an app on a mobile phone, another server, and so on.
URL (or URI)
The URL (Universal Resource Locator) or URI (Universal Resource Identifier) is the address, possibly including query parameters, which is sent to Jarvis. A URL has the general format:
[scheme://][userinfo@]host[:port][/path][?query]
scheme
is either http
or https
.userinfo@
is HTTP Basic authentication user credentials if authentication is being used.host
is the Jarvis server domain name or IP address.port
is the optional port number. It defaults to 80 for http
or 443 for https
.path
is the endpoint for the request.query
are the query parameters, if any, for the request.
HTTP method
The HTTP protocol defines several request "methods" that a client may use to request the server to perform different operations. When you open a web browser on a URL, the browser is typically using the GET HTTP method to retrieve the requested content. Other HTTP methods include POST, PUT, DELETE, PATCH, and HEAD; each one designed to indicate the operation the server should perform.
JSON
JSON stands for JavaScript Object Notation and is a flexible notation for representing data arrays and objects. Dyalog APL has a system function, ⎕JSON
, which easily converts between JSON and APL arrays/namespaces.
REST
REST stands for REpresentational State Transfer and is a design pattern for APIs. An API that follows this design pattern is termed "RESTful". When a RESTful API is called, the server will transfer to the client a representation of the state of the requested resource.
Paradigms
Jarvis supports two operational paradigms that we term JSON and REST. A Jarvis server can run only one paradigm at a time. One of the first decisions you'll need to make when using Jarvis is which web service paradigm to use. The paradigm will determine protocol for how a client will interact with Jarvis. This section provides information to help you decide which paradigm is most appropriate for your application.
The JSON paradigm
The JSON paradigm may seem quite natural to the APLer in that the endpoints (functions) take a data argument and return a data result. The argument and result can be as complex as you like, provided that they can be represented using JSON.
- The endpoints are the names of APL functions that are called to satisfy the request. You can specify which functions you want to expose as endpoints for your service to the client.
- The client uses the HTTP POST method and passes the parameters for the request as JSON in the request body.
- The payload (body) of the request is automatically converted by Jarvis from JSON to an APL array and passed as the right argument to your function.
- Your function should return an APL array which Jarvis then converts to JSON and returns to the client in the response.
- Your application needs to know nothing about JSON, HTTP or web services.
The REST paradigm
RESTful web services use standard HTTP methods to perform operations on resources. A resource (endpoint) is the path
in the request's URL. The resource could be a physical resource like a file or a virtual resource that is constructed dynamically by your code. There are several other "RESTful design" principles or constraints, but they are beyond the scope of this document.
- Operations are typically implemented corresponding to standard HTTP methods:
- GET – read a resource
- POST – create a resource
- PUT – update/replace a resource
- PATCH – update/modify a resource
- DELETE – delete a resource
- With Jarvis, you specify which methods you want your service to support.
- You then implement an APL function with the same name as each method.
- Resources are specified in the
path
of the request URL. - Depending on how you design the service API, parameters, if any, can be passed in the URL, the query string, the body of the request, or some combination thereof.
- The function you write is passed the request object and it's up to you to parse the URL, payload, headers, and query parameters to determine what to do and what the arguments are.
- You decide on the content type and format of the payload of the response. Common response content types for RESTful web services are JSON, XML or HTML.
- In general, the JSON paradigm is quicker and easier to implement, but a properly implemented REST paradigm
JSON contrasted with REST
In many cases, the same functionality can be implemented using either paradigm.
With JSON, endpoints are the names of APL functions that you want to expose with your web service. You write one APL function per operation you want to perform.
With REST, endpoints identify resources and the HTTP method determines the operation to perform on the resource. You write one APL function for each HTTP method your web service will support.
To compare the two paradigms, let's imagine you want to retrieve the total of invoice 45 for customer 231.
JSON Example
One way to implement this using the JSON paradigm might be to:
- specify that the client should provide the arguments as a JSON object with a "customer" element and an "invoicenum" element. For this example, it might look like
- write an APL function called
GetInvoiceTotal
which would take a namespace as its argument. The namespace will contain elements named "customer" and "invoice"∇ namespace← GetInvoiceTotal namespace;costs [1] ⍝ the namespace argument was created by Jarvis from the JSON object in the request [2] costs←namespace.customer GetInvoiceItems namespace.invoice ⍝ retrieve the invoice item costs pseudo-code [3] namespace.total←+/costs ⍝ insert a total element into the namespace ∇
- Jarvis will then convert the result, in this case the updated namespace, to JSON
{"customer":231,"invoicenum":45,"total":654.32}
and return it to the client
REST Example
Using the REST paradigm, you might specify a resource like /customer/231/invoice/45/total
. Since this is a "read" operation, you would use the HTTP GET method to retrieve it.
- You would write a function named GET
(the same as the HTTP method) which would be passed the HTTP request object. The Endpoint
element of the request object will be '/customer/231/invoice/45/total'
.
- Your function would need to parse the endpoint to determine what is being requested and then retrieve the information.
- Your function would set the content-type for the response payload as well as format the retrieved information and assign it to the payload.
Best Practices
For all but the simplest of Jarvis-based services, we recommend:
- Store the code that implements your endpoints in text files which Jarvis will load upon startup. Set the
CodeLocation
configuration setting to the folder name that contains the text files. - Use a Jarvis configuration file to specify all non-default configuration settings.
Core Usage Pattern
There are four basic steps to running a Jarvis service.
- Write the APL code which implements the endpoints of your service.
- Create an instance of the
Jarvis
class. - Configure the instance.
- Run the instance.
Everything else - from running the service locally to deploying it as a secure, cloud-hosted, load-balanced service is built on upon these four steps.
Write the APL code that implements the endpoints
The Jarvis paradigm you choose (JSON or REST) will determine how to write your endpoints.
- JSON - you will write an APL function to implement each endpoint. The function name is the endpoint name. See the JSON Paradigm section for more information.
- REST - you will write an APL function for each HTTP method your service will support. The function name is the same as the HTTP method name. See the REST Paradigm section for more information.
Create an instance of the Jarvis
class
While you can use the ⎕NEW
system function to create an instance of Jarvis
, the recommended technique is to use Jarvis.New
.
j←Jarvis.New args
args
can be one of:
''
- create the instance using the default settings. Any non-default settings that you plan to use will need to be set before starting the instance.'path-to-a-Jarvis-config-file'
- create the instance using the settings specified in a Jarvis config file. A Jarvis config file is a JSON (or JSON5) file that contains Jarvis configuration settings.namespace-reference
- create the instance using the named settings contained in a namespace. The namespace can contain only variables with names of Jarvis configuration settings.- A positional vector of up to 4 elements containing
Port CodeLocation 'Paradigm' 'JarvisConfig'
. You do not need to provide all parameters - only those up to the last parameter you need to use. For instance, if you need to specify'REST'
as the paradigm, you'll also need to supplyPort
andCodeLocation
.
Note that you can always set additional configuration settings after creating the instance with any of the above methods (but before running the instance).
Assuming that the file /JarvisConfig.json
contains:
{"Port":80, "CodeLocation":"/myJarvisApp/", "Paradigm":"REST"}
and
namespace←⎕JSON ⊃⎕NGET '/JarvisConfig.json'
the following are equivalent.
j←Jarvis.New '' ⋄ j.(Port CodeLocation Paradigm)←80 '/myJarvisApp' 'REST'
j←Jarvis.New '/JarvisConfig.json'
j←Jarvis.New namespace
j←Jarvis.New 80 '/myJarvisApp/' 'REST'
CodeLocation
CodeLocation
specifies where Jarvis should look for the code that implements your endpoints. It can be
- a reference to, or the name of, a namespace in the workspace. For example, either
#.MyApp
and'#.MyApp'
will work if your application code is in the namespace#.MyApp
. - a character vector representing the path to the folder that contains your application code. If the path is relative, Jarvis attempts to determine the root folder from which to the path is relative to what it's relative to as follows:
- If Jarvis is running in a saved workspace, it uses the folder where the workspace is located.
- Otherwise, if you have specified a Jarvis config file, Jarvis will use the folder where the config file is located.
- Otherwise, if Jarvis can determine the path for its source file, it will use that.
- Finally, it will default to the current folder for your Dyalog session as determined by
(1 ⎕NPARTS '')
. Using a relative path can be useful for making your Jarvis service more portable, but it's important to make sure to understand the process above. For instance, if you have been running Jarvis from aCLEAR WS
by dynamically loading it and then you save your application to a named workspace, Jarvis could wind up looking in a potentially different folder if the workspace is stored elsewhere than the Jarvis config file.
Configure the Jarvis
instance
Having created a Jarvis
instance, you can set any configuration parameter prior to starting the instance. This includes being able to override parameters that may have been loaded from a Jarvis config file. Details about each of the parameters can be found in Settings.
Run the Jarvis
instance
Use j.Start
to start the Jarvis
instance. Use j.Stop
to stop Jarvis
. You can run j.Start
again to restart Jarvis
.
Jarvis's JSON paradigm was developed to make it easy to expose the functionality of your APL application as a web service. The endpoints of your service are simply APL functions that take an array as a right argument and return an error as a result.
How Jarvis's JSON mode works
You write an APL function for each endpoint of your service
Each endpoint function should at a minimum take an APL array as a right argument and return an APL array as its result. The name of the endpoint is the name of your function - so, it's best to not use characters in your endpoint function names that aren't easily supported in URLs. Your functions should reside in the namespace specified by [`CodeLocation]
The client sends a request
It doesn't matter what the client is - it could be a browser, an app on a phone, Dyalog's HttpCommand
, curl, or any program capable of sending and receiving HTTP messages. To call one of your service's endpoints, the client's request should:
- Specify the
- Use the HTTP POST method in order to send the request payload.
- Include a
content-type: application/json
header in the request's headers. - Format its payload as JSON.
Example
curl -H "content-type: application/json" -X POST -d [1,3,5] http://localhost:8080/sum
Advanced Usage
- The
AllowGETs
setting will enable HTTP GET method to be used as well - by defaultAllowGETs
is disabled. - The
AllowFormData
setting will enableJarvis
to receive payloads that usecontent-type: multipart/form-data
- by defaultAllowFormData
is disabled.
Jarvis
receives the request
When Jarvis
receives the request, it verifies that the request is well-formed. If there is a problem parsing the request, Jarvis
will respond to the client with a 400-series HTTP status code and message. Assuming the request is well-formed, Jarvis
will convert the request's JSON payload to an APL array using ⎕JSON
.
Jarvis
calls your endpoint function
Jarvis
passes the APL array as the right argument to your endpoint function. If your function is dyadic or ambivalent, Jarvis
will pass the HttpRequest
object as the left argument. Your function should return an APL array result.
Advanced Usage
Jarvis has a few specific places where you can "inject" your own APL code to perform actions like additional request validation, authentication, and so on. Two such places are available after Jarvis
receives the request, but before calling your endpoint function. These are:
ValidateRequestFn
specifies the name of a function to call for every request thatJarvis
receives.AuthenticateFn
specified the name of a function to call to perform authentication.
Jarvis
sends the response to the client
Jarvis
will convert the APL array result into JSON format using ⎕JSON⍠'HighRank' 'Split'
and send the JSON back to the client as the payload of the response.
Jarvis's REST paradigm was developed to make it possible to deploy your APL application using a REST API. REST APIs are more applicable when managing a collection of resources. HTTP-based REST web services, like Jarvis, use standard HTTP methods (GET, POST, PUT, DELETE, etc) to create, retrieve, and manipulate resources.
There are six guiding principles of REST. The degree to which you adhere to these principles is completely up to you.
How Jarvis's REST mode works
You write an APL function for each HTTP method your service will support
Rather than writing a function for each endpoint as in the JSON paradigm, you will write a monadic function for each of the HTTP methods that your web service will support. Your functions should reside in the namespace specified by CodeLocation
.
You specify which HTTP methods your REST service will support using the RESTMethods
setting. For instance, setting RESTMethods←'Get'
indicates that your service will support only HTTP GET requests. Such requests will call the #.CodeLocation.Get
function, passing the HTTP request as its right argument. For the purposes of this document, we'll call the request right argument Request
.
Your Get
function would then look at the resource being requested by parsing Request.Endpoint
element. If DefaultContentType
is set to 'application/json'
(the default), your function can return an APL array which Jarvis
will convert to JSON. If you are not using 'application/json'
, then you will need to:
- use
Request.SetContentType
to set an appropriate content type - set the
Request.Response.Payload
to the content you want to send back to the client
The client sends a request
It doesn't matter what the client is - it could be a browser, an app on a phone, Dyalog's HttpCommand
, curl, or any program capable of sending and receiving HTTP messages. To interact with a resource, the client should:
- Specify the resource in the request URL
- Specify the HTTP method appropriate to the operation being requested
- If the request includes a payload, specify an appropriate
content-type
header
Example
To retrieve a hypothetical list of orders for customer with id 123, one might make a request like:
resp←HttpCommand.Get 'http://localhost:8080/customers/123/orders'
Jarvis
receives the request
When Jarvis
receives the request, it verifies that the request is well-formed. If there is a problem parsing the request, Jarvis
will respond to the client with a 400-series HTTP status code and message.
Jarvis
calls your method function
Jarvis
passes the Request
object as the right argument to the function appropriate for the HTTP method being used. It is up to your function to parse Request.Endpoint
to determine the resource being requested. As noted above, if the response payload's content-type
is 'application/json'
your function can return an APL array which Jarvis
will automatically convert to JSON. Otherwise, your function is responsible for setting the Request.Response.Payload
and Request.ContentType
appropriately.
If the requested resource is not found, or some other issue occurs, your function should fail the request with an appropriate HTTP status code using Request.Fail
. For example, an HTTP status code of 404 means that the requested resource was not found and you would use Request.Fall 404
to set the status code.
Advanced Usage
Jarvis has a few specific places where you can "inject" your own APL code to perform actions like additional request validation, authentication, and so on. Two such places are available after Jarvis
receives the request, but before calling your function. These are:
ValidateRequestFn
specifies the name of a function to call for every request thatJarvis
receives.AuthenticateFn
specified the name of a function to call to perform authentication.
Jarvis
sends the response to the client
Jarvis
will format a proper HTTP response and send it to the client.
Ended: Usage
Reference ↵
Settings ↵
The settings documentation is broken up into groups of related settings as follows.
Group | Description |
---|---|
Operational | Settings related to the operation of the Jarvis server. Examples include CodeLocation , JarvisConfig and Paradigm . |
Conga | Settings specific to Conga, Dyalog's TCP/IP framework. |
JSON Mode | Settings specific to running a Jarvis service in JSON mode. |
REST Mode | Settings specific to running a Jarvis service in REST mode. |
Session | Settings related to using sessions with Jarvis to maintain server-side state. |
User Hooks | Settings that allow you to specify "hook" functions to perform tasks like application initialization, session initialization, and authentication. |
Container | Settings related to running a Jarvis service in a containerized environment like Docker. |
CORS | Settings related to Cross Origin Resource Sharing which can enable calls to your Jarvis service to be made from webpages in other domains. |
Shared | Settings that are shared by all instances of Jarvis. |
CodeLocation
Description | Prior to starting a Jarvis instance, CodeLocation specifies where Jarvis will look for your endpoint code. CodeLocation can be any of:
CodeLocation is set to a reference to the namespace containing your endpoint code. |
Default | '#' |
Examples | j.CodeLocation←#.myEndpoints ⍝ reference to namespace j.CodeLocation←'#.myEndpoints' ⍝ name of namespace j.Codelocation←'/home/me/myEndpoints' ⍝ folder j.CodeLocation←'/home/me/myEndpoints.apln' ⍝ file containing namespace definition |
Notes | If the environment variable DYALOG_JARVIS_CODELOCATION exists, it will override any other setting for CodeLocation . |
ConnectionTimeout
Description | ConnectionTimeout specifies the the amount of time in seconds that a connection may be idle before being closed. Jarvis will not close a connection that is currently being serviced by a long-running endpoint. |
Default | 30 |
Examples | j.ConnectionTimeout←120 ⍝ 2 minute timeout |
Notes | ConnectionTimeout is used by Jarvis 's "housekeeping" to prevent inactive connections from accumulating. |
Debug
Description | Setting Debug to a non-zero value will enable various types of debugging and reporting to take place. The valid values for Debug are:
Debug values are additive. For example 9 would stop on any error as well as enable Conga event reporting are |
Default | 0 |
Examples | j.Debug←2 ⍝ stop just before executing any user code |
Notes | While it is possible to set Debug to ¯1 to enable all forms of debugging, be mindful that additional values for Debug may be added in the future and this could lead to unintended behavior. |
DefaultContentType
Description | DefaultContentType specifies the HTTP content-type for Jarvis 's response if no content-type header has been specified by the user's endpoint code. |
Default | 'application/json; charset=utf-8' |
Examples | j.DefaultContentType←'application/xml; charset=utf-8' |
Notes | DefaultContentType should only be set when most of the responses from your endpoints will have a content-type other than 'application/json' . For individual responses that use a different content-type, set request.ContentType . |
ErrorLevelInfo
Description | ErrorLevelInfo specifies how much information to include in the HTTP status message when an untrapped error occurs and Jarvis returns an HTTP status code of 500. Valid settings are:
|
Default | 1 |
Examples | j.ErrorInfoLevel←2 ⍝ include function name and line number |
Hostname
Description | Hostname is the name of the host that Jarvis will insert into the "host" header of the response. If a response payload from Jarvis needs to include URLs pointing to other endpoints within the service, Hostname can be used to construct those URLS. |
Default | '' which means that Jarvis will use the result of 2 ⎕NQ # 'TCPGetHostID' (the IP address of the server on the local network) |
Examples | j.Hostname←'www.myJarvis.com' |
Notes | 2 ⎕NQ # 'TCPGetHostID' returns the IP address on the local network, which isn't of much use if the client is accessing Jarvis from an external network. Hostame exists to address this problem by providing an external address to Jarvis . |
HTTPAuthentication
Description | HTTPAuthentication indicates the HTTP authentication scheme that will be used to authenticate requests. Currently only HTTP Basic authentication is supported. Valid settings are:
|
Default | 'basic' |
Examples | j.HTTPAuthentication←'' ⍝ disable HTTP basic authentication |
Notes | See HTTP Basic Authentication |
JarvisConfig
Description | JarvisConfig is the name of the JSON (or JSON5) file, if any, that contains your Jarvis configuration. |
Default | '' |
Examples | j.JarvisConfig←'/home/myapp/jarvisconfig.json |
Notes | If you specify a relative path to the Jarvis configuration file, Jarvis will consider it to be relative to the current working directory as returned by 1 ⎕NPARTS '' |
LoadableFiles
Description | If CodeLocation specifies a folder from which to load your endpoints' code, LoadableFiles specifies a comma-delimited set of patterns to match when selecting files to load into workspace. |
Default | '*.apl?,*.dyalog' |
Examples | j.LoadableFiles←'*.apln,*.aplf,*.aplc' |
Notes | Dyalog has evolved its "code in files" methodology. In its early days, the .dyalog extension was used almost exclusively. Over time, and with the advent of Link , the common practice is to the use of file extension to indicate the particular type of APL object contained within the file - .aplf for a function, .apln for a namespace, .aplc for a class, and .apla for an array. |
Logging
Description | Logging is a Boolean setting that determines whether Jarvis will display certain internal log messages to the session. |
Default | 1 |
Examples | j←Jarvis.New '' j.Start ⍝ default is Logging←1 2024-12-06 @ 11.34.23.890 - Starting Jarvis 1.18.4 2024-12-06 @ 11.34.23.913 - Conga copied from C:\Program Files\Dyalog\Dyalog APL-64 19.0 Unicode/ws/conga 2024-12-06 @ 11.34.23.915 - Local Conga v3.5 reference is #.Jarvis.[LIB] 2024-12-06 @ 11.34.23.923 - Jarvis starting in "JSON" mode on port 8080 2024-12-06 @ 11.34.23.927 - Serving code in # 2024-12-06 @ 11.34.23.931 - Click http://192.168.223.134:8080 to access web interface 0 Server started j.Stop 2024-12-06 @ 11.34.35.564 - Stopping server... 0 Server stopped j.Logging←0 ⍝ turn off logging j.Start 0 Server started |
Notes | The messages controlled by Logging are internal, operational, messages.Request and HTTP logging capabilities will be available in a forthcoming Jarvis release. |
Paradigm
Description | Paradigm specifies the mode in which Jarvis will operate. Current valid values are:
|
Default | 'JSON |
Examples | j.Paradigm←'REST' |
Notes | You should set Paradigm before starting your Jarvis instance. |
UseZip
Description | UseZip is a Boolean that tells Jarvis whether to send a compressed response payload if the client will accept it as indicated by the "accept-encoding" header in the client request. Valid values are:
|
Default | 0 |
Examples | j.UseZip←1 |
Notes | At present only "gzip" and "deflate" content-encodings are supported. ZipLevel controls the level of compression employed. |
ZipLevel
Description | ZipLevel is an integer value between 0 and 9 and specifies the level of compression to use when Jarvis compresses the response payload (see UseZip ). Higher values result in a higher degree of compression albeit at the cost of performance. |
Default | 3 which seems to provide the best trade-off of compression versus speed. |
Examples | j.ZipLevel←6 |
A stateless web service means that each request from a client to the server is treated as an independent transaction that is unrelated to any previous request. In other words, the server does not store any information about the state of the client between requests. There are many good reasons for implementing a stateless web service including improved scalability, reliability, and independence. However, in some cases it may make sense to maintain some state on the server. Jarvis's sessions are intended to allow you to maintain state in the server.
See Using Sessions for more information.
SessionTimeout
Description | SessionTimeout controls whether Jarvis will use sessions. It also specifies how long before a session will time out and be removed. Valid settings are:
|
Default | 0 - do not use sessions |
Examples | j.SessionTimeout←10 ⍝ timeout after 10 minutes of inactivity |
SessionIdHeader
Description | SessionIdHeader is the name of the HTTP header or HTTP cookie that will contain the session identifier. Every sessioned request must include this session ID in order to access the session state information on the server. |
Default | 'Jarvis-SessionID' |
Examples | j.SessionIdHeader←'gandalf' |
SessionUseCookie
Description | SessionUseCookie controls whether the session id is sent using an HTTP header or an HTTP cookie. In either case, the header or the cookie name will be specified by SessionIdHeader . Valid settings are:
|
Default | 0 |
Examples | j.SessionUseCookie←1 ⍝ use a cookie for the session id |
Notes | Using an HTTP cookie can be more convenient, especially if the client is a browser. When Jarvis creates session it will send the cookie in its response and then the browser will automatically include the cookie in every subsequent request. |
SessionPollingTime
Description | SessionPollingTime controls how often, in minutes, Jarvis polls for timed-out sessions. |
Default | 1 |
Examples | j.SessionPollingTime←5 |
Notes | When using sessions, Jarvis starts a session monitor in a separate thread. The session monitor loops continuously checking for timed-out sessions. SessionPollingTime controls the time between each loop. |
SessionCleanupTime
Description | SessionCleanupTime controls how often, in minutes, Jarvis purges remaining information about timed-out sessions. |
Default | 60 |
Examples | j.(SessionCleanupTime←SessionTimeout) ⍝ set to not retain any information after a session times out |
Notes | When a session times out, Jarvis erases the namespace associated with the session, but leaves information about the session having existed. SessionCleanupTime determines when that remaining information is removed. The intent was to give you the opportunity to inform the client that their session timed out if they send a request after the session has timed out, but before the remaining information is expunged. |
These settings apply when using Jarvis's JSON paradigm.
AllowFormData
Description | AllowFormData controls whether Jarvis will accept requests with a content-type of 'multipart/form-data' . This makes it more convenient when using a form in a web browser as the client or to upload a file. Valid settings are:
|
Default | 0 |
Examples | j.AllowFormData←1 ⍝ enable multipart/form-data content |
AllowGETs
Description | AllowGETs controls whether Jarvis will accept HTTP GET requests to call endpoints. Normally, Jarvis will accept only HTTP POST requests to access an endpoint, but there may be cases when it's convenient to all simple requests using HTTP GET. Valid settings are:
|
Default | 0 |
Examples | j.AllowGETs←1 ⍝ accept GET requests |
Notes | Parameters to the endpoint being called should be specified using URL-encoded properly formatted JSON in the URL query string. For instance, if you have a sum←+/ endpoint and you want to sum the array [1,2,3] , you would need to use the endpoint and query string /sum?%5B1%2C2%2C3%5D (which is URL-encoded /sum?[1,2,3] ). |
HTMLInterface
Description | HTMLInterface controls whether and how Jarvis will provide an HTML interface. Valid settings are:
|
Default | 1 if using JSON mode, 0 otherwise |
Examples | j.HTMLInterface←'/myjarvis/web/' ⍝ HTML content is in the folder /myjarvis/web/ |
JSONInputFormat
Description | JSONInputFormat controls the format of the request's JSON payload when converted to APL. Valid settings are:
'Format ' option for ⎕JSON . |
Default | D |
Examples | j.JSONInputFormat←'M' ⍝ use the matrix inport format for ⎕JSON |
Notes | JSONInputFormat also has effect when using Jarviss REST paradigm if [ ParsePayload](./settings-rest.md#parsepayload) is set to 1`. |
Report404InHTML
Description | When a requested endpoint is not found, Jarvis will always respond by setting the response HTTP status code to 404 and HTTP status message to 'Not Found' . Report404InHTML controls whether Jarvis will also return a simple "not found" HTML page in its response payload. This is potentially useful when the client is a web browser. Valid settings are:
|
Default | 1 |
Examples | j.Report404←0 ⍝ disable sending the "not found" HTML page |
Notes | Report404InHTML has effect only if the HTMLInterface is enabled. |
These settings apply when using Jarvis's REST paradigm.
ParsePayload
Description | ParsePayload controls whether Jarvis automatically convert JSON and XML request payload to an APL format using either ⎕JSON or ⎕XML as appropriate.Valid settings are:
|
Default | 1 - parse JSON and XML payloads |
Examples | j.ParsePayload←0 ⍝ do not parse JSON and XML payloads |
Notes | The format for parsed JSON payloads is controlled by JSONInputFormat . |
RESTMethods
Description | RESTMethods specifies which HTTP methods will be supported by your REST web service. It is a comma-delimited character vector of HTTP method names and optionally, the name of the APL function that will service that HTTP method. Each comma-delimited segment consists of a case-insensitive HTTP method name ('get' 'GET' 'gEt' will all match GET). The method name can be optionally followed by a '/' and the function name which implements the handler for that HTTP method. If no function name is supplied, the function name will be the case-sensitive HTTP method. |
Default | 'Get,Post,Put,Delete,Patch,Options' |
Examples | j.RESTMethods←'Get,post/handlePOST' In this example our service will accept HTTP GET and POST requests.
|
Notes | Jarvis does not place a restriction on the HTTP method names, meaning that you could potentially invent your own "HTTP" methods.j.RESTMethods←'Get,Bloofo' ⍝ allow GET and BLOOFO . |
"Hook" functions are functions you write to inject custom behavior at specific points in Jarvis
's execution. You then assign the name of the function to the appropriate "hook". Hook functions can be located in #.CodeLocation
- Jarvis
will exclude them from being considered as endpoint functions. By default, no hook functions are defined; you need to define only the hook functions, if any, that are needed for your web service.
AppCloseFn
Description | AppCloseFn is the name of the niladic, function to be called when Jarvis is stopped. This function could do things like closing database connections, managing log files, etc. The function may return a 2-element array of (rc msg) where rc is an integer return code (0 means "okay") and msg is a character vector message. If the function does not return a result, the Jarvis will return the return code and message that was set prior to calling AppCloseFn . |
Default | '' |
Examples | j.AppCloseFn←'ShutDown' |
AppInitFn
Description | AppInitFn is the name of the monadic, result-returning function to be called when Jarvis is started. This function is called before Jarvis starts listening for requests. This function could do things like establishing database connections or other application initialization. The function should return a 2-element array of (rc msg) where rc is an integer return code (0 means "okay") and msg is a character vector message. If the function is monadic, its right argument is a reference to the Jarvis instance. |
Default | '' |
Examples | j.AppInitFn←'Startup' |
Notes | If your function returns a non-0 return code, Jarvis will exit. |
AuthenticateFn
Description | AuthenticateFn is the name of monadic, result-returning function to be called when you need to authenticate a request. The right argument to the function is the Request instance. The function result should either be:
|
Default | '' |
Examples | j.AuthenticateFn←'Authenticate' |
Notes | See Authentication for more information about how to authenticate an HTTP request. |
SessionInitFn
Description | SessionInitFn is the name of a monadic, result-returning function that can perform session initialization if your web service is using sessions. The right argument is the Request instance, which we'll call req . The reference to the session namespace is req.Session . The integer function result should be either:
|
Default | '' |
Examples | j.SessionInitFn←'InitSession |
Notes | See Using Sessions for more information. |
ValidateRequestFn
Description | ValidateRequestFn is the name of a monadic, result-returning function that will be called for every request that Jarvis receives. ValidateRequestFn gives you the opportunity to perform additional validation on a request. The right argument is the Request instance. The function result should either be:
|
Default | '' |
Examples | j.ValidateRequestFn←'Validate' |
Notes | See Validation for more information. |
Jarvis uses Conga for TCP/IP communications. Jarvis
's Conga settings are used to configure the Conga's operation. See the Conga User Guide for more detailed information on specific settings.
Once started, Jarvis
maintains a reference to to Conga library in the LDRC
field. This enables you to manage query and/or manage Conga settings directly if you need to. For instance, j.LDRC.Tree '.'
will return the entire Conga object tree.
AcceptFrom
Description | AcceptFrom allows you to limit Jarvis incoming connections to a specific set of IP address ranges. AcceptFrom is either one or two character vectors that specify IPV4 and/or IPV6 address ranges. Each vector is a comma-delimited set of IP ranges. |
Default | '' |
Examples | j.AcceptFrom←'192.168.1.1/127,10.17.221.67/75' |
Notes | This setting is documented as AllowEndPoints in the Conga User Guide. Unlike AllowEndPoints , you do not need to specify 'IPV4' or 'IPV6' as Jarvis can automatically determine which IP version is intended. |
BufferSize
Description | BufferSize specifies the maximum HTTP headers length that Jarvis will accept. The intent is to block malicious requests that attempt to overwhelm the server by sending huge requests. |
Default | 10000 |
Examples | j.BufferSize←5000 ⍝ allow up to 5000 bytes of HTTP header data |
Notes | BufferSize can be used in conjunction with DOSLimit to mitigate Denial of Service (DOS) attacks. |
DenyFrom
Description | Similar to AcceptFrom , DenyFrom allows you to deny incoming connections from a specific set of IP address ranges. DenyFrom is either one or two character vectors that specify IPV4 and/or IPV6 address ranges. Each vector is a comma-delimited set of IP ranges. |
Default | '' |
Examples | j.DenyFrom←'192.168.1.1/127,10.17.221.67/75' |
Notes | This setting is documented as DenyEndPoints in the Conga User Guide. Unlike DenyEndPoints , you do not need to specify 'IPV4' or 'IPV6' as Jarvis can automatically determine which IP version is intended. |
DOSLimit
Description | To reduce possible Denial Of Service (DOS) attacks, DOSLimit is used to limit the size of HTTP payloads that Jarvis will accept. |
Default | ¯1 which indicates to use the Conga default value of 10485760 |
Examples | j.DOSLimit←100000 ⍝ assumes no message will exceed 100000 bytes |
Notes | You should specify a DOSLimit large enough to accept the largest message you anticipate receiving. |
FIFO
Description | FIFO controls how Conga will process incoming requests. Setting FIFO to 1 will cause Conga to process requests in a "First In, First Out" order. Setting FIFO to 0 will cause Conga to process requests according to Conga's ReadyStrategy setting. |
Default | 1 |
Examples | j.FIFO←0 ⍝ turn FIFO mode off |
Notes | This setting is documented as EnableFifo in the Conga User Guide. |
Port
Description | Port is port number that Jarvis will listen on. |
Default | 8080 |
Examples | j.Port←22361 |
Notes | Allocating ports below 1024 on Linux typically requires root privileges due to security reasons. |
RootCertDir
Description | When running Jarvis over HTTPS, RootCertDir is the path to a folder containing public root certificates. |
Default | '' |
Examples | Set RootCertDir to the public root certificates folder installed with Dyalog.dir←1 1⊃1 ⎕NPARTS 2 ⎕NQ '.' 'GetCommandLineArgs' j.RootCertDir←dir,'PublicCACerts' |
Notes | This setting is documented as RootCertDir in the Conga User Guide. See Security for more information. |
Priority
Description | Priority is the GnuTLS priority string when using secure communications. Priority specifies the TLS session's handshake algorithms when negotiating a secure connection. |
Default | 'NORMAL:!CTYPE-OPENPGP' |
Examples | j.Priority←'NORMAL:-MD5' ⍝ use the default without HMAC-MD5 |
Notes | Setting Priority to something other than the default requires an in-depth understanding of TLS session negotiation. Don't change it unless you know know what you're doing. |
Secure
Description | Secure is a Boolean setting that controls whether Jarvis will use TLS. Valid settings are:
|
Default | 0 |
Examples | j.Secure←1 ⍝ enable secure communications |
Notes | Using TLS requires configuring several settings, see Using TLS. |
ServerCertSKI
Description | Under Windows, when using the Microsoft Certificate Store to obtain the server certificate for Jarvis to use, ServerCertSKI is the Server Certificate Subject Key Identifier of the certificate. |
Default | '' |
Examples | j.ServerCertSKI←'aca7d8f00691129ea0bc3613a00ed8ea9a5e55f5' |
Notes | The subject key identifier is a 40 byte hexadecimal string. For more information, see Using TLS. |
ServerCertFile
Description | ServerCertFile is the name of the file containing the server's public certificate. |
Default | '' |
Examples | j.ServerCertFile←'/etc/mycerts/publiccert.pem' |
Notes | For more information, see Using TLS. |
ServerKeyFile
Description | ServerKeyFile is the name of the file containing the server's private key. |
Default | '' |
Examples | j.ServerKeyFile←'/etc/mycerts/privatekey.pem' |
Notes | Never share your private key file. For more information, see Using TLS. |
ServerName
Description | ServerName is the Conga name for the Jarvis server. You can specify the name or have it Conga assign it. |
Default | Assigned by Conga in the format 'SRVnnnnnnnn' where nnnnnnnn begins at 00000000 and is incremented when a Jarvis server using the same Conga instance is started. |
Examples | )copy conga Conga j1←Jarvis.New 8080 j2←Jarvis.New 8081 j3←Jarvis.New 8082 j3.ServerName←'MyJarvis' (j1 j2 j3).Start (j1 j2 j3).ServerName SRV00000000 SRV00000001 MyJarvis |
Notes | ServerName can be useful when interacting with Conga, particularly when debugging. For example:j3.(LDRC.Describe ServerName) 0 MyJarvis Server Listen LDRC is Jarvis 's local reference to the Conga library. |
SSLValidation
Description | SSLValidation is employed as part of the certificate checking process and is more fully documented in the Conga User Guide. |
Default | 64 - request but do not require a client certificate |
Examples | j.SSLValidation←128 ⍝ require a valid certificate |
Notes | For more information, see Using TLS. |
WaitTimeout
Description | WaitTimeout is the number of milliseconds that Jarvis will wait in its listening loop before timing out. |
Default | 15000 - 15 seconds |
Examples | j.WaitTimeout←60000 ⍝ wait a minute before timing out |
Notes | Conga servers sit in a "wait" loop listening for communications from clients. If no communications occur before WaitTimeout has passed, Conga will signal a "Timeout" event and reiterate the "wait" loop. |
CORS, or Cross-Origin Resource Sharing, is a security feature implemented by web browsers to control how resources on a web page can be requested from another domain outside the domain from which the resource originated. It helps prevent malicious websites from accessing sensitive data on other websites.
When a web page makes a request to a different domain (cross-origin request), the browser checks if the server allows such requests by looking at the CORS headers in the server's response. If the headers indicate that the request is allowed, the browser permits the resource to be accessed; otherwise, it blocks the request.
CORS is essential for enabling secure communication between different web applications and APIs while protecting users from potential security risks.
Without modification, Jarvis's default CORS settings will allow most CORS requests. For more information about CORS, see CORS.
EnableCORS
Description | EnableCORS is a Boolean setting which enables or disables CORS support in Jarvis . Valid values are:
|
Default | 1 |
Examples | j.EnableCORS←0 ⍝ disable CORS support |
CORS_Origin
Description | CORS_Origin specifies the domains from which requests are allowed. Valid values are:
|
Default | '*' - requests from all domains are allowed. |
Examples | j.CORS_Origin←'https://foo.example' ⍝ allow requests only from https://foo.example |
CORS_Methods
Description | CORS_Methods controls which HTTP methods that will be allowed in cross-origin requests. Valid values are:
|
Default | ¯1 |
Examples | j.CORS_Methods←'GET,POST' |
Notes | This setting applies only to preflighted requests. You may also directly set the Access-Control-Allow-Methods header, which will override the CORS_Methods setting. |
CORS_Headers
Description | CORS_Headers controls what additional headers will be allowed in a CORS request. Valid values are:
|
Default | '*' |
Examples | j.CORS_Headers←'X-Custom-Header' |
Notes | By default, only the CORS-safelisted response headers are exposed to the client. This setting applies only to preflighted requests. You may also directly set the Access-Control-Allow-Headers header, which will override the CORS_Headers setting. |
CORS_MaxAge
Description | CORS_MaxAge indicates, in seconds, how long the results of a preflight request can be cached. |
Default | 60 |
Examples | j.CORS_MaxAge←600 ⍝ set to 10 minutes (600 seconds) |
Notes | This setting applies only to preflighted requests. You may also directly set the Access-Control-Max-Age header, which will override the CORS_MaxAge setting. |
Most Jarvis configuration options should be set using a Jarvis configuration file. A few environment variables are particularly useful in the context of running Jarvis in a container.
DYALOG_JARVIS_PORT
Description | If set, DYALOG_JARVIS_PORT is the port that the Jarvis container will listen on. It overrides both the Jarvis default and any port specified in the Jarvis configuration. |
Default | '' |
Examples | DYALOG_JARVIS_PORT=8888 |
Notes | DYALOG_JARVIS_PORT allows you to specify different port numbers for each instance of the Jarvis container. |
DYALOG_JARVIS_CODELOCATION
Description | If set, DYALOG_JARVIS_CODELOCATION is the path to a folder containing your Jarvis endpoint code. |
Default | '' |
Examples | DYALOG_JARVIS_CODELOCATION=/myJarvisApp |
DYALOG_JARVIS_THREAD
Description | DYALOG_JARVIS_THREAD controls which thread Jarvis will run on. Valid values are:
|
Default | '' |
Examples | DYALOG_JARVIS_THREAD=1 |
Notes | If you need to debug your Jarvis service in a container, you can configure Dyalog to use RIDE and set DYALOG_JARVIS_THREAD to any of debug , '' or 'auto' to remotely access your Jarvis service. |
Ended: Settings
Methods ↵
Ended: Methods
Ended: Reference
Advanced Topics ↵
Ended: Advanced Topics
About ↵
MIT License
Copyright (c) 2021 Dyalog
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.