% This LaTeX document was generated using the LaTeX backend of PlDoc,
% The SWI-Prolog documentation system



\section{Supporting JSON}

\label{sec:jsonsupport}

From \url{http://json.org,} "
JSON (JavaScript Object Notation) is a lightweight data-interchange
format. It is easy for humans to read and write. It is easy for machines
to parse and generate. It is based on a subset of the JavaScript
Programming Language, Standard ECMA-262 3rd Edition - December 1999.
JSON is a text format that is completely language independent but uses
conventions that are familiar to programmers of the C-family of
languages, including C, C++, C\#, Java, JavaScript, Perl, Python, and
many others. These properties make JSON an ideal data-interchange
language."

Although JSON is nowadays used a lot outside the context of web
applications, SWI-Prolog's support for JSON started life as part of the
HTTP package. SWI-Prolog supports two Prolog representations for JSON
terms. The first and oldest map JSON objects to a term
\verb$json(PropertyList)$ and use the \verb$@$ functor to disambiguate e.g. \const{null}
from the string \verb$"null"$, leading to \verb$@(null)$. As of SWI-Prolog version
7, JSON objects may be represented using \textit{dict} objects and JSON strings
using Prolog strings. Predicates following this convention are suffixed
with \verb$_dict$, e.g. \predref{json_read_dict}{2}. For example, given the JSON document

\begin{code}
{ "name": "Bob", "children": ["Mary", "John"], "age":42, "married": true }
\end{code}

we get either (using \predref{json_read}{2}):

\begin{code}
json([name='Bob', children=['Mary', 'John'], age=42, married= @(true)]).
\end{code}

or (using \predref{json_read_dict}{2}):

\begin{code}
_{age:42, children:["Mary", "John"], married:true, name:"Bob"}
\end{code}

The SWI-Prolog JSON interface consists of three libraries:

\begin{itemize}
    \item \file{library(http/json)} provides support for the core JSON object
serialization and parsing.
    \item \file{library(http/json_convert)} converts between the primary
representation of JSON terms in Prolog and more application
oriented Prolog terms. E.g. \verb$point(X,Y)$ vs. \verb$object([x=X,y=Y])$.
    \item \file{library(http/http_json)} hooks the conversion libraries into
the HTTP client and server libraries.

\subsection{library(http/json): Reading and writing JSON serialization}

\label{sec:json}

\begin{tags}
    \tag{author}
Jan Wielemaker\mtag{See also}- \file{http_json.pl} links JSON to the HTTP client and server modules. \\- \file{json_convert.pl} converts JSON Prolog terms to more comfortable
terms.
\end{tags}

This module supports reading and writing JSON objects. This library
supports two Prolog representations (the \textit{new} representation is only
supported in SWI-Prolog version 7 and later):

\begin{itemize}
    \item The \textbf{classical} representation is provided by \predref{json_read}{3} and
\predref{json_write}{3}. This represents a JSON object as \verb$json(NameValueList)$,
a JSON string as an atom and the JSON constants \const{null}, \const{true} and
\const{false} as @(null), @(true) and @false.
    \item The \textbf{new} representation is provided by \predref{json_read_dict}{3} and
\predref{json_write_dict}{3}. This represents a JSON object as a dict, a JSON
string as a Prolog string and the JSON constants using the Prolog
atoms \const{null}, \const{true} and \const{false}.
\end{itemize}

\vspace{0.7cm}

\begin{description}
    \predicate[det]{atom_json_term}{3}{?Atom, ?JSONTerm, +Options}
Convert between textual representation and a JSON term. In
\textit{write} mode (\arg{JSONTerm} to \arg{Atom}), the option

\begin{description}
    \termitem{as}{Type}
defines the output type, which is one of \const{atom} (default),
\const{string}, \const{codes} or \const{chars}.
\end{description}

    \predicate[det]{json_read}{2}{+Stream, -Term}
\nodescription
    \predicate[det]{json_read}{3}{+Stream, -Term, +Options}
Read next JSON value from \arg{Stream} into a Prolog term. The
canonical representation for \arg{Term} is:

\begin{itemize}
    \item A JSON object is mapped to a term \verb$json(NameValueList)$, where
NameValueList is a list of Name=Value. Name is an atom
created from the JSON string.
    \item A JSON array is mapped to a Prolog list of JSON values.
    \item A JSON string is mapped to a Prolog atom
    \item A JSON number is mapped to a Prolog number
    \item The JSON constants \const{true} and \const{false} are mapped -like JPL-
to @(true) and @(false).
    \item The JSON constant \const{null} is mapped to the Prolog term
@(null)
\end{itemize}

Here is a complete example in JSON and its corresponding Prolog
term.

\begin{code}
{ "name":"Demo term",
  "created": {
    "day":null,
    "month":"December",
    "year":2007
  },
  "confirmed":true,
  "members":[1,2,3]
}
\end{code}

\begin{code}
json([ name='Demo term',
       created=json([day= @null, month='December', year=2007]),
       confirmed= @true,
       members=[1, 2, 3]
     ])
\end{code}

The following options are processed:

\begin{description}
    \termitem{null}{+NullTerm}
\arg{Term} used to represent JSON \const{null}. Default @(null)
    \termitem{true}{+TrueTerm}
\arg{Term} used to represent JSON \const{true}. Default @(true)
    \termitem{false}{+FalseTerm}
\arg{Term} used to represent JSON \const{false}. Default @(false)
    \termitem{value_string_as}{+Type}
Prolog type used for strings used as value. Default
is \const{atom}. The alternative is \const{string}, producing a
packed string object. Please note that \const{codes} or
\const{chars} would produce ambiguous output and is therefore
not supported.
\end{description}

\begin{tags}
    \tag{See also}
\predref{json_read_dict}{3} to read a JSON term using the version 7
extended data types.
\end{tags}

    \predicate[det]{json_write}{2}{+Stream, +Term}
\nodescription
    \predicate[det]{json_write}{3}{+Stream, +Term, +Options}
Write a JSON term to \arg{Stream}. The JSON object is of the same
format as produced by \predref{json_read}{2}, though we allow for some more
flexibility with regard to pairs in objects. All of Name=Value,
Name-Value and Name(Value) produce the same output.

Values can be of the form \#(\arg{Term}), which causes \arg{Term} to be
\textit{stringified} if it is not an atom or string. Stringification is
based on \predref{term_string}{2}.

The version 7 \textit{dict} type is supported as well. Optionally, if
the dict has a \textit{tag}, a property "type":"tag" can be added to
the object. This behaviour can be controlled using the \const{tag}
option (see below). For example:

\begin{code}
?- json_write(current_output, point{x:1,y:2}).
{
  "x":1,
  "y":2
}
\end{code}

\begin{code}
?- json_write(current_output, point{x:1,y:2}, [tag(type)]).
{
  "type":"point",
  "x":1,
  "y":2
}
\end{code}

In addition to the options recognised by \predref{json_read}{3}, we process
the following options are recognised:

\begin{description}
    \termitem{width}{+Width}
\arg{Width} in which we try to format the result. Too long lines
switch from \textit{horizontal} to \textit{vertical} layout for better
readability. If performance is critical and human
readability is not an issue use \arg{Width} = 0, which causes a
single-line output.
    \termitem{step}{+Step}
Indentation increnment for next level. Default is 2.
    \termitem{tab}{+TabDistance}
Distance between tab-stops. If equal to Step, layout
is generated with one tab per level.
    \termitem{serialize_unknown}{+Boolean}
If \const{true} (default \const{false}), serialize unknown terms and
print them as a JSON string. The default raises a type
error. Note that this option only makes sense if you can
guarantee that the passed value is not an otherwise valid
Prolog reporesentation of a Prolog term.
\end{description}

If a string is emitted, the sequence \verb$</$ is emitted as
\verb$<\/$. This is valid JSON syntax which ensures that JSON
objects can be safely embedded into an HTML \verb$<script>$
element.

    \predicate[semidet]{is_json_term}{1}{@Term}
\nodescription
    \predicate[semidet]{is_json_term}{2}{@Term, +Options}
True if \arg{Term} is a json term. \arg{Options} are the same as for
\predref{json_read}{2}, defining the Prolog representation for the JSON
\const{true}, \const{false} and \const{null} constants.

    \predicate[det]{json_read_dict}{2}{+Stream, -Dict}
\nodescription
    \predicate[det]{json_read_dict}{3}{+Stream, -Dict, +Options}
Read a JSON object, returning objects as a dicts. The
representation depends on the options, where the default is:

\begin{itemize}
    \item String values are mapped to Prolog strings
    \item JSON \const{true}, \const{false} and \const{null} are represented using these
Prolog atoms.
    \item JSON objects are mapped to dicts.
    \item Optionally, a \const{type} field in an object assigns a tag for
the dict.
\end{itemize}

The predicate \predref{json_read_dict}{3} processes the same options as
\predref{json_read}{3}, but with different defaults. In addition, it
processes the \const{tag} option. See \predref{json_read}{3} for details about
the shared options.

\begin{description}
    \termitem{tag}{+Name}
When converting to/from a dict, map the indicated JSON
attribute to the dict \textit{tag}. No mapping is performed if \arg{Name}
is the empty atom ('', default). See \predref{json_read_dict}{2} and
\predref{json_write_dict}{2}.
    \termitem{default_tag}{+Tag}
Provide the default tag if the above \const{tag} option does not
apply.
    \termitem{null}{+NullTerm}
Default the atom \const{null}.
    \termitem{true}{+TrueTerm}
Default the atom \const{true}.
    \termitem{false}{+FalseTerm}
Default the atom \const{false}
    \termitem{end_of_file}{+ErrorOrTerm}
Action on reading end-of-file. See \predref{json_read}{3} for details.
    \termitem{value_string_as}{+Type}
Prolog type used for strings used as value. Default
is \const{string}. The alternative is \const{atom}, producing a
packed string object.
\end{description}

    \predicate[det]{json_write_dict}{2}{+Stream, +Dict}
\nodescription
    \predicate[det]{json_write_dict}{3}{+Stream, +Dict, +Options}
Write a JSON term, represented using dicts. This is the same as
\predref{json_write}{3}, but assuming the default representation of JSON
objects as dicts.

    \predicate[det]{atom_json_dict}{3}{+Atom, -JSONDict, +Options}
\nodescription
    \predicate[det]{atom_json_dict}{3}{-Text, +JSONDict, +Options}
Convert between textual representation and a JSON term
represented as a dict. \arg{Options} are as for \predref{json_read}{3}.
In \textit{write} mode, the addtional option

\begin{description}
    \termitem{as}{Type}
defines the output type, which is one of \const{atom},
\const{string} or \const{codes}.
\end{description}
\end{description}

\subsection{library(http/json_convert): Convert between JSON terms and Prolog application terms}

\label{sec:jsonconvert}

\begin{tags}
\mtag{To be done}- Ignore extra fields. Using a partial list of \textit{extra}? \\- Consider a sensible default for handling JSON \const{null}. Conversion
to Prolog could translate @null into a variable if the desired type
is not \const{any}. Conversion to JSON could map variables to \const{null},
though this may be unsafe. If the Prolog term is known to be
non-ground and JSON @null is a sensible mapping, we can also use
this simple snipit to deal with that fact.

\begin{code}
        term_variables(Term, Vars),
        maplist(=(@null), Vars).
\end{code}

\end{tags}

The idea behind this module is to provide a flexible high-level mapping
between Prolog terms as you would like to see them in your application
and the standard representation of a JSON object as a Prolog term. For
example, an X-Y point may be represented in JSON as \verb${"x":25, "y":50}$. Represented in Prolog this becomes \verb$json([x=25,y=50])$, but
this is a pretty non-natural representation from the Prolog point of
view.

This module allows for defining records (just like \file{library(record)}) that
provide transparent two-way transformation between the two
representations.

\begin{code}
:- json_object
        point(x:integer, y:integer).
\end{code}

This declaration causes \predref{prolog_to_json}{2} to translate the native Prolog
representation into a JSON Term:

\begin{code}
?- prolog_to_json(point(25,50), X).

X = json([x=25, y=50])
\end{code}

A \predref{json_object}{1} declaration can define multiple objects separated by a
comma (,), similar to the \predref{dynamic}{1} directive. Optionally, a declaration
can be qualified using a module. The conversion predicates
\predref{prolog_to_json}{2} and \predref{json_to_prolog}{2} first try a conversion associated
with the calling module. If not successful, they try conversions
associated with the module \const{user}.

JSON objects have no \textit{type}. This can be solved by adding an extra field
to the JSON object, e.g. \verb${"type":"point", "x":25, "y":50}$. As Prolog
records are typed by their functor we need some notation to handle this
gracefully. This is achieved by adding +Fields to the declaration. I.e.

\begin{code}
:- json_object
        point(x:integer, y:integer) + [type=point].
\end{code}

Using this declaration, the conversion becomes:

\begin{code}
?- prolog_to_json(point(25,50), X).

X = json([x=25, y=50, type=point])
\end{code}

The predicate \predref{json_to_prolog}{2} is often used after \predref{http_read_json}{2} and
\predref{prolog_to_json}{2} before \predref{reply_json}{1}. For now we consider them seperate
predicates because the transformation may be too general, too slow or
not needed for dedicated applications. Using a seperate step also
simplifies debugging this rather complicated process.\vspace{0.7cm}

\begin{description}
    \predicate[multifile]{current_json_object}{3}{Term, Module, Fields}
Multifile predicate computed from the \predref{json_object}{1}
declarations. \arg{Term} is the most general Prolog term representing
the object. \arg{Module} is the module in which the object is defined
and \arg{Fields} is a list of \verb$f(Name, Type, Default, Var)$, ordered by
Name. Var is the corresponding variable in \arg{Term}.

    \predicate{json_object}{1}{+Declaration}
Declare a JSON object. The declaration takes the same format as
using in \predref{record}{1} from \file{library(record)}. E.g.

\begin{code}
?- json_object
      point(x:int, y:int, z:int=0).
\end{code}

The type arguments are either types as know to \file{library(error)} or
functor names of other JSON objects. The constant \const{any}
indicates an untyped argument. If this is a JSON term, it
becomes subject to \predref{json_to_prolog}{2}. I.e., using the type
\verb$list(any)$ causes the conversion to be executed on each element
of the list.

If a field has a default, the default is used if the field is
not specified in the JSON object. Extending the record type
definition, types can be of the form (Type1\Sbar{}Type2). The type
\const{null} means that the field may \textit{not} be present.

Conversion of JSON to Prolog applies if all non-defaulted
arguments can be found in the JSON object. If multiple rules
match, the term with the highest arity gets preference.

    \predicate[det]{prolog_to_json}{2}{:Term, -JSONObject}
Translate a Prolog application \arg{Term} into a JSON object term.
This transformation is based on \Sneck{} \predref{json_object}{1} declarations.
If a \predref{json_object}{1} declaration declares a field of type
\const{boolean}, commonly used thruth-values in Prolog are converted
to JSON booleans. Boolean translation accepts one of \const{true},
\const{on}, \verb$1$, @true, \const{false}, \const{fail}, \const{off} or \verb$0$, @false.

\begin{tags}
\mtag{Errors}- \verb$type_error(json_term, X)$ \\- instantiation_error
\end{tags}

    \predicate[det]{json_to_prolog}{2}{+JSON, -Term}
Translate a \arg{JSON} term into an application term. This
transformation is based on \Sneck{} \predref{json_object}{1} declarations. An
efficient transformation is non-trivial, but we rely on the
assumption that, although the order of fields in \arg{JSON} terms is
irrelevant and can therefore vary a lot, practical applications
will normally generate the \arg{JSON} objects in a consistent order.

If a field in a json_object is declared of type \const{boolean}, @true
and @false are translated to \const{true} or \const{false}, the most
commonly used Prolog representation for truth-values.
\end{description}

\subsection{library(http/http_json): HTTP JSON Plugin module}

\label{sec:httpjson}

\begin{tags}
\mtag{See also}- JSON Requests are discussed in \url{http://json.org/JSONRequest.html} \\- \file{json.pl} describes how JSON objects are represented in Prolog terms. \\- \file{json_convert.pl} converts between more natural Prolog terms and json
terms.
\end{tags}

This module adds hooks to several parts of the HTTP libraries, making
them JSON-aware. Notably:

\begin{itemize}
    \item Make \predref{http_read_data}{3} convert \verb$application/json$ and
\verb$application/jsonrequest$ content to a JSON term.
    \item Cause \predref{http_open}{3} to accept \verb$post(json(Term))$ to issue a POST
request with JSON content.
    \item Provide HTTP server and client utility predicates for reading
and replying JSON:

\begin{shortlist}
    \item \predref{http_read_json}{2}
    \item \predref{http_read_json}{3}
    \item \predref{http_read_json_dict}{2}
    \item \predref{http_read_json_dict}{3}
    \item \predref{reply_json}{1}
    \item \predref{reply_json}{2}
    \item \predref{reply_json_dict}{1}
    \item \predref{reply_json_dict}{2}
\end{shortlist}

    \item Reply to exceptions in the server using an JSON document rather
then HTML if the \verb$Accept$ header prefers application/json over
text/html.
\end{itemize}

Typically JSON is used by Prolog HTTP servers. This module supports two
JSON representations: the classical representation and the new
representation supported by the SWI-Prolog version 7 extended data
types. Below is a skeleton for handling a JSON request, answering in
JSON using the classical interface.

\begin{code}
handle(Request) :-
      http_read_json(Request, JSONIn),
      json_to_prolog(JSONIn, PrologIn),
      <compute>(PrologIn, PrologOut),         % application body
      prolog_to_json(PrologOut, JSONOut),
      reply_json(JSONOut).
\end{code}

When using dicts, the conversion step is generally not needed and the
code becomes:

\begin{code}
handle(Request) :-
      http_read_json_dict(Request, DictIn),
      <compute>(DictIn, DictOut),
      reply_json(DictOut).
\end{code}

This module also integrates JSON support into the http client provided
by \file{http_client.pl}. Posting a JSON query and processing the JSON reply
(or any other reply understood by \predref{http_read_data}{3}) is as simple as
below, where Term is a JSON term as described in \file{json.pl} and reply is of
the same format if the server replies with JSON.

\begin{code}
      ...,
      http_post(URL, json(Term), Reply, [])
\end{code}

\vspace{0.7cm}

\begin{description}
\qpredicate[multifile]{http_client}{http_convert_data}{4}{+In, +Fields, -Data, +Options}Hook implementation that supports reading JSON documents. It
processes the following option:

\begin{description}
    \termitem{json_object}{+As}
Where \arg{As} is one of \const{term} or \const{dict}. If the value is \const{dict},
\predref{json_read_dict}{3} is used.
\end{description}

    \predicate[semidet]{is_json_content_type}{1}{+ContentType}
True if \arg{ContentType} is a header value (either parsed or as
atom/string) that denotes a JSON value.

    \predicate[semidet,multifile]{json_type}{1}{?MediaType}
True if \arg{MediaType} is a JSON media type. \qpredref{http_json}{json_type}{1} is
a multifile predicate and may be extended to facilitate
non-conforming clients.

\begin{arguments}
\arg{MediaType} & is a term \arg{Type}/\arg{SubType}, where both \arg{Type} and
\arg{SubType} are atoms. \\
\end{arguments}

\qpredicate[semidet,multifile]{http}{post_data_hook}{3}{+Data, +Out:stream, +HdrExtra}Hook implementation that allows \predref{http_post_data}{3} posting JSON
objects using one of the forms below.

\begin{code}
http_post(URL, json(Term), Reply, Options)
http_post(URL, json(Term, Options), Reply, Options)
\end{code}

If Options are passed, these are handed to \predref{json_write}{3}. In
addition, this option is processed:

\begin{description}
    \termitem{json_object}{As}
If \arg{As} is \const{dict}, \predref{json_write_dict}{3} is used to write the
output. This is default if \verb$json(Dict)$ is passed.
\end{description}

\begin{tags}
    \tag{To be done}
avoid creation of intermediate data using chunked output.
\end{tags}

    \predicate[det]{http_read_json}{2}{+Request, -JSON}
\nodescription
    \predicate[det]{http_read_json}{3}{+Request, -JSON, +Options}
Extract \arg{JSON} data posted to this HTTP request. \arg{Options} are
passed to \predref{json_read}{3}. In addition, this option is processed:

\begin{description}
    \termitem{json_object}{+As}
One of \const{term} (default) to generate a classical Prolog
term or \const{dict} to exploit the SWI-Prolog version 7 data type
extensions. See \predref{json_read_dict}{3}.
\end{description}

\begin{tags}
\mtag{Errors}- \verb$domain_error(mimetype, Found)$ if the mimetype is
not known (see \predref{json_type}{1}). \\- \verb$domain_error(method, Method)$ if the request method is not
a \verb$POST$, \verb$PUT$ or \verb$PATCH$.
\end{tags}

    \predicate[det]{http_read_json_dict}{2}{+Request, -Dict}
\nodescription
    \predicate[det]{http_read_json_dict}{3}{+Request, -Dict, +Options}
Similar to \predref{http_read_json}{2},3, but by default uses the version 7
extended datatypes.

    \predicate[det]{reply_json}{1}{+JSONTerm}
\nodescription
    \predicate[det]{reply_json}{2}{+JSONTerm, +Options}
Formulate a JSON HTTP reply. See \predref{json_write}{2} for details.
The processed options are listed below. Remaining options are
forwarded to \predref{json_write}{3}.

\begin{description}
    \termitem{content_type}{+Type}
The default \verb$Content-type$ is \verb$application/json; charset=UTF8$. \verb$charset=UTF8$ should not be required
because JSON is defined to be UTF-8 encoded, but some
clients insist on it.
    \termitem{status}{+Code}
The default status is 200. REST API functions may use
other values from the 2XX range, such as 201 (created).
    \termitem{json_object}{+As}
One of \const{term} (classical json representation) or \const{dict}
to use the new dict representation. If omitted and Term
is a dict, \const{dict} is assumed. SWI-Prolog Version 7.
\end{description}

    \predicate[det]{reply_json_dict}{1}{+JSONTerm}
\nodescription
    \predicate[det]{reply_json_dict}{2}{+JSONTerm, +Options}
As \predref{reply_json}{1} and \predref{reply_json}{2}, but assumes the new dict based
data representation. Note that this is the default if the outer
object is a dict. This predicate is needed to serialize a list
of objects correctly and provides consistency with
\predref{http_read_json_dict}{2} and friends.
\end{description}
\end{itemize}

