6.3. Web Services

Some sites provide access to remote services, rather than performing local computation. In particular, a site could provide access to a Web service. The Orc library provides sites which perform basic HTTP requests and manipulate JSON and XML data representations; these capabilities are sufficient to interact with many simple web services, especially RESTful services.

6.3.1. HTTP

The HTTP site provides a simple mechanism to send GET and POST requests to a URL.

  • HTTP(U), where U is a java.net.URL, publishes a site which accepts HTTP requests on the URL U.

  • HTTP(S) parses the string S as an absolute URL U, and then behaves as HTTP(U).

  • HTTP(S,Q) maps the record Q to a URL query string QS by translating each record binding to a query pair, escaping characters if necessary. The call then behaves as HTTP(S+QS).

The HTTP site publishes a site (call it H) with methods get and post:

  • H.get() performs a GET request on the URL used to create H.

  • H.post(P,T) performs a POST request with payload P on the URL used to create H. The request's Content-Type header is set to T.

If the request is successful, the response is published as a single string, which may be translated to a more useful representation by other library sites.

6.3.2. Data Processing

Web services often expect inputs or provide outputs in a particular format, such as XML or JSON. The Orc library provides sites which convert between string representations of these data formats and structured representations which Orc can manipulate.

JSON

JSON (JavaScript Object Notation) is a lightweight data format often used by Web services, especially by services with simple interfaces. The structure of JSON values maps onto Orc values, using nested lists and records.

The library sites ReadJSON and WriteJSON convert between string representations of JSON values and Orc representations of those values. ReadJSON parses a string representation of JSON and creates an Orc value, where each JSON array becomes an Orc list, each JSON object becomes an Orc record, and literal values map to their Orc counterparts. WriteJSON performs the inverse operation, taking a structured value of this form and producing a string representation of an equivalent JSON value. If j is an Orc representation of a JSON value, then ReadJSON(WriteJSON(j)) is equal to j.

XML

XML (Extensible Markup Language) is a structured data format used in many contexts, including Web services.

The library sites ReadXML and WriteXML convert between string representations of XML values and Orc representations of those values. ReadXML parses a string representation of XML and creates an Orc representation, which can be manipulated by Orc's XML library sites. WriteXML performs the inverse operation, taking an Orc representation of XML and serializing it to a string. If x is an Orc representation of an XML fragment, then ReadXML(WriteXML(x)) is equal to x.

Unlike JSON, the structure of XML does not map directly to Orc's structured values. Instead, Orc provides a set of library sites and functions which manipulate XML in a manner similar to Orc's datatypes. Orc's XML manipulation capabilities are currently incomplete; in particular, it does not handle namespaces. All constructed elements have the default namespace, element and attribute tags have no prefixes, and element matching discards namespace and prefix information. For more comprehensive XML manipulation, use of underlying platform capabilities (such as Scala or Java libraries) is recommended.

Primitive XML Sites

There are three library sites that construct XML nodes directly. Each of these sites may also be used in a call pattern to match the corresponding constructed value.

  • XMLElement(tag, attr, children) creates a new XML element with the tag given by string tag, the set of attributes specified by the record attr, and the sequence of child elements given by the list children. Each value mapped by attr is converted to a string in the XML representation. attr may be an empty record. Each element of children must be an XML node. children may be an empty list.

  • XMLText(txt) creates a new XML text node whose content is the string txt. Characters in txt which are not permitted in XML text will be encoded.

  • XMLCData(txt) creates a new XML CDATA node whose content is the string txt. Characters in txt are not encoded.

The library site IsXML verifies that its argument is an XML node of some type. IsXML(x) publishes x if x is an XML node; otherwise it halts silently.

Manipulating XML

The library provides two records, xml and xattr, to manipulate XML nodes more conveniently than by using the primitive XML sites. Each record has two members, apply and unapply, that are both functions. The apply function builds XML values, and the unapply function is used in pattern matching.

xml is convenient when working only with the tree structure of XML, and not with the attributes of the element nodes. Note that xml's apply and unapply members are not inverses of each other.

  • xml(t, cs) returns a new XML element with the tag t, the list of children cs, and no attributes. If any element of cs is not an XML node, it is converted to a string and enclosed in a text node.

  • The pattern xml(ptag, pchild) matches an XML element. The pattern ptag is matched against the element tag. The pattern pchild is matched against each child of the element; it is a multimatch, so it may succeed multiple times and produces a result on each success. Additionally, when pchild matches a text or CDATA node rather than an element node, it is bound to the string contents of the node, rather than the node itself.

xattr is convenient when working only with the attributes of XML element nodes, and not with the overall tree structure.

  • xattr(x, attr) returns a new XML element which is the same as x except that all bindings in the record attr have been added to the attributes of the element. If attr binds any attribute names already bound in x, attr takes precedence and overwrites those bindings.

  • The pattern xattr(pe, pa) matches an XML element. The pattern pe is matched against a copy of the element with no attributes. The pattern pa is matched against a record containing the attributes of the element.

6.3.3. SOAP Web Services

Though Orc does not provide direct bindings to SOAP web services, it is possible to access such services through Java bindings. Frameworks such as JAX-WS map SOAP web service functionality to Java classes; these classes can then be used as sites in Orc.

6.3.4. Examples

Random Bytes from Fourmilab
{-
   Make a request to the Fourmilab HotBits service 
   to produce a sequence of 4 random bytes in hex.
-}

{- Returns a string of n random hexadecimal bytes -}
def randombytes(n) =
  val query = {. nbytes = n, fmt = "xml" .} 
  val location = "https://www.fourmilab.ch/cgi-bin/Hotbits"
  val response = HTTP(location, query).get()
  val xml("hotbits", xml("random-data", data)) = ReadXML(response) 
  data.trim()

randombytes(4)

6.3.5. Related Links