API Reference
The Berkeley Server API serves to interact with decision trees published to Berkeley Bridge WebServers.
Where is the Berkeley Bridge Server API currently used?
- the client-side framework from Berkeley Bridge (‘presentation layer’) and
- third parties that need to create and manage cases, but let the actual user-interaction be handled by the client-side framework from Berkeley Bridge.
- automated regression tests of decision trees
The part of the API described here covers authentication, model querying, and session management: all things necessary to create an administrative shell or portal to the Berkeley Bridge models and sessions.
The part of the API necessary to create a client framework for running an actual decision tree is left out of this documentation. The administrative part that is used for managing users, domains and model rights and changing server settings is not covered.
Getting started
The API responds in JSON format when fmt=json
. Without this
parameter, the API responds in HTML.
Requests to the API are in the form of HTTP parameter=value
requests,
since the API has its roots in talking to a browser (so no such things
as a JSON body inside requests).
All requests that expect JSON as output need
fmt=json
as a parameter.
Note on documentation
Since the API responses can get quite large, the example responses focus on just the parts of interest to a certain section.
Since fmt=json
is always required, it is considered understood and
left out in the endpoint documentation for brevity’s sake. The example
sections do list this parameter.
Quick start
Create a link to a publicly accessible model
In the example below, we will use the API to create a link with which a user without an account can create a case for a model that is publicly accessible.
let modelname = 'klantendag',
signature = { method : "POST" },
server = 'yourserver',
template = 'bb.html';
fetch('/login?fmt=json', signature)
.then(res => res.json())
.then(({uniqueid, models}) => {
let model = models.find((m)=>m.realmodelname === modelname);
if (!model)
throw `No such model: ${modelname}`;
return `${server}/${template}?uniqueid=${uniqueid}&modelid=${model.modelid}`
})
.then(link => console.log(link))
.catch(err => console.warn(err))
Analysis of the above code
First, one logs in without any credentials with /login?fmt=json
.
The response is a JSON object, which lists all models that are publicly available in the models
property.
We then search the model list for the model we are interested in.
If we do not find our model, we throw an error.
If we do, we create a link, using the uniqueid
that is a top-level property of the returned JSON and the modelid
property of the model we just found.
You see the link created uses the ‘template’ bb.html
. This is the default HTML entry page for a Berkeley Web Server. This HTML page may be variable if the server hosts multiple presentation layers.
NOTE the method in the request signature is set to
POST
here; theGET
method would be equally valid though.
You can use this link as a regular link for the user to follow:
<a href="https://example.com/bb.html?uniqueid=UID&modelid=MID">link text</a>
… or as the src
attribute of an <iframe>
with a fallback link inside:
<iframe src="https://example.com/bb.html?uniqueid=UID&modelid=MID">
<a href="https://example.com/bb.html?uniqueid=UID&modelid=MID">link text</a>
</iframe>
Create a link to a model for an authenticated and authorised user
In this example, we will create a session for a user with an account.
let modelname = 'klantendag',
server = 'yourserver',
signature = { method : "POST" },
template = 'bb.html',
username = 'john',
password = 'secret passphrase never to be guessed';
fetch(`/login?fmt=json&username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`, signature)
.then(res => res.json())
.then(({uniqueid, models}) => {
let model = models.find((m) => m.realmodelname === modelname);
if (!model)
throw `No such model: ${modelname}`;
return `${server}/${template}?uniqueid=${uniqueid}&modelid=${model.modelid}`
})
.then(link => console.log(link))
.catch(err => console.warn(err))
Analysis of the above code
First, as with the anonymous example above, one logs in with /login?fmt=json
. This time however, we do provide their credentials.
The response is a JSON object, which lists all models that are available for that user in the models
property.
We then search the model list for the model we are interested in.
If we do not find our model, we throw an error.
If we do, we create a link, using the uniqueid
that is a top-level property of the returned JSON and the modelid
property of the model we just found.
You see the link created uses the ‘template’ bb.html
. This is the default HTML entry page for a Berkeley Web Server. This HTML page may be variable if the server hosts multiple presentation layers.
NOTE the method in the request signature is set to
POST
here; theGET
method would be equally valid though.
You can use this link as a regular link for the user to follow:
<a href="https://example.com/bb.html?uniqueid=UID&modelid=MID">link text</a>
… or as the src
attribute of an <iframe>
with a fallback link inside:
<iframe src="https://example.com/bb.html?uniqueid=UID&modelid=MID">
<a href="https://example.com/bb.html?uniqueid=UID&modelid=MID">link text</a>
</iframe>
Basic concepts used in this API
Before delving any further, let’s pause and look at the core concepts used inside this API.
Model
A model is a decision tree.
Models get created by authors using the desktop software Berkeley Studio. These authors publish the models to a Berkeley Webserver.
This API takes it from there.
Case
A case is a specific run-through of a model (a decision tree), and contains all answered questions. A case may be (auto-)saved, listed, re-opened, copied, used as a template and, finally, deleted.
A case may last as long as a user session does, or remain on the server until explicitly deleted.
Unique ID
What other API’s call a session token.
Session ID
Id for a specific case.
Model name
modelname
represents the model filename, as in modelname.mdl
. It
can be considered stable and your best bet to use for long-term reference.
Ready for some confusion? In the response to
/menu
this one is calledrealmodelname
.
Model description
modeldescription
represents what is actually the model description, i.e. a
pretty, free-form name, configurable in the server.
This is prone to change at an author’s or administrator’s whim. Do not use it for long-time reference, unless maybe you are very close with the author or administrator.
Ready for some more confusion? In the response to
/menu
this is calledmodelname
.
Model ID
The modelid
is the id used in API communication to reference a model within a session.
Chances are high that it may point to another model entirely when used with a different server, or to no model at all.
Logging in
The API uses anonymous login, user credentials or SSO solutions in order to create a session.
The use of SSO solutions is explained elsewhere.
Anonymously
Logging in anonymously:
# Logging in anonymously
curl "https://example.com/login?fmt=json"
The simplest case of logging in is to create an anonymous session.
With an anonymous session one can access publicly accessible decision trees (models).
HTTP Request
GET/POST https://example.com/login
Logging in with just
/login
will give you an anonymous session, ready to experiment
With user credentials
Logging in with user credentials:
# Provide user credentials
curl "https://example.com/login?fmt=json&password=secret&username=johndoe"
# Or with newer, leaner, API:
curl -d username=johndoe -d password=secret https://example.com/api/login
Make sure to replace
secret
andjohndoe
with your credentials.
Registered users may access all publicly accessible decision trees and decision trees they have published or to which they have explicitly been given access.
Registered users are also allowed to save and re-open sessions on the server and to change their account details. These are options that can be turned on or off on the Server.
HTTP Request
GET/POST https://example.com/login
Query Parameters
Parameter | Default |
---|---|
password | empty |
username | empty |
Logging in with a
/login?username=...&password=...
will give you a session for a specific user
Skipping login
As a shortcut, the login step may be skipped, if what you want to do first is to create a new session for a known modelname or modelid.
After logging in
A successful login returns a uniqueid:
{ "uniqueid": "DTTAYWFVKQXIJWOKGGRLDHXVPPBBDI", ... }
After logging in, the API returns a JSON object with a temporary token
called uniqueid
.
The API expects this uniqueid as a parameter to all subsequent requests, and also returns it in all of its successful responses.
All requests other than
login
use auniqueid
parameter, e.g.uniqueid=UHIEHQUIWYWEIHUIWE
.
Listing decision trees
Get list of available models
curl "https://example.com/menu?uniqueid=DTTAYWFVKQXIJWOKGGRLDHXVPPBBDI&fmt=json"
Sample response for
/menu
{
"models": [
{
"realmodelname": STRING,
"modelname": STRING,
"modelid": INT,
"version": GUID,
"yours": BOOL,
"language": STRING,
"authorname": STRING,
"authorinfo": STRING,
"modelinfo": STRING,
"serverinstructions": STRING,
"completed": true,
"lastupdate": "/Date(INT)/",
"company": STRING
}
]
}
Once you have logged in and acquired the uniqueid
, use /menu
to get a list of
available models.
realmodelname
represents the model name, as in realmodelname.mdl
.
modelname
represents what is actually the model description, i.e. a
pretty, free-form name, configurable in the server.
In all other parts of the API
modelname
refers to what is here calledrealmodelname
. In those areasmodeldescription
refers what is here calledmodelname
.
The modelid
is the id used subsequently in API communication.
Use
modelid
to talk with the API about a model. Userealmodelname
if you need to look up the model in this list, and usemodelname
to show to an end user.
yours
means that the account used for authentication is the (only) one
allowed to publish this model.
version
is a GUID uniquely identifying the current version of the
model. It is used for cache-busting otherwise equally named resources.
Working with cases
A case is a specific run-through of a model (a decision tree), and contains all answered questions. A case may be (auto-)saved, listed, re-opened, copied, used as a template and, finally, deleted.
Creating a new case
/open
without asessionid
opens a new case
curl "https://example.com/open?modelid=M&fmt=json"
{
"sessionid" : GUID,
"casename" : STRING // Human name to identify this session
}
To create a new case, call the endpoint /open
HTTP Request
GET/POST https://example.com/open
Query Parameters
Parameter | Description | Required |
---|---|---|
uniqueid | empty | if model is private |
modelid | model to create case for | yes |
Sending along custom parameters when creating a new case
It is possible to send custom parameters along with the request to
create a new case.
As long as you prefix your parameters to give it a ‘namespace’ and do not use bb:
as a
prefix, there is no change of colliding with internal parameters.
Custom parameters are any prefixed parameters you may want to make available to the model author.
You may for example choose my:
as a prefix and use
open?modelname=mymodel&my:param=3
as a request.
The model author then may pick up the parameter my:param
with the function
getparambyname('my:param')
.
The prefix bb:
is a reserved prefix, i.e. do not use it, since it
may collide with parameters used by (future versions of) this API
JavaScript example sending my:param along
You can test the following JavaScript after publishing the accompanying model to your own server. Remember to replace 'https://yourserver'
with your own address.
let server = "https://yourserver",
signature = { method : "POST" };
fetch("/login?fmt=json", signature)
.then(res => res.json())
.then(({uniqueid}) => fetch(`/menu?uniqueid=${uniqueid}&fmt=json`, signature))
.then(res => res.json())
.then(({uniqueid, models}) => {
let model = models.find((m) => m.realmodelname === "customparam"),
url = `/open?uniqueid=${uniqueid}&modelid=${model.modelid}&my:param=3&fmt=json`;
return fetch(url, signature);
})
.then(res => res.json())
.then(({uniqueid, modelid, sessionid}) => {
return `${server}/bb.html?uniqueid=${uniqueid}&modelid=${modelid}&sessionid=${sessionid}`
})
.then(link => console.log(link))
When following the link logged at the end of this code in a browser, the model will echo your custom parameter back to you as follows:
You entered: 3
Analysis of the above code
First, one logs in with /login?fmt=json
. Credentials may be given here too (username=USERNAME&password=PASSWORD
). Otherwise login will be anonymous.
Then, with the uniqueid
, a request is done to /menu
. This will list all models available to the logged in user in the models
property.
We then search the model list for the model we are interested in.
After that, we perform a request to /open
a new case on the server, with the uniqueid
, the modelid
we just got and our custom parameter my:param
.
When that request returns, we have a running session that may access the parameter my:param
with the Studio function getparambyname('my:param')
.
The last step creates a link, using the uniqueid
, the modelid
and the sessionid
returned in the request that creates the new case. The sessionid
uniquely identifies the case.
You see the link created uses bb.html
. This is the default HTML entry page for a Berkeley Web Server. This HTML page may be variable if the server hosts multiple presentation layers.
NOTE the method in the request signature is set to
POST
here; theGET
method would be equally valid though.
Listing cases for a model
A generic call to /menu
gives some general info about cases: how
many there are, and whether or not the user is allowed to get a
listing of all previous runs through a certain model (caselistingallowed
below):
{
"models": [
{
"modelid": INT,
"selected": BOOL,
"casecount": INT,
"caselistingallowed": BOOL
}
]
}
If case listing is allowed, we can fire the /menu
request with the model in question:
curl "https://example.com/menu?modelid=MODELID&uniqueid=DTTAYWFVKQXIJWOKGGRLDHXVPPBBDI&fmt=json"
The server response will then contain an array of cases for the model in question, and also whether the user is supposed to
- delete a case from this listing (
showdeleteinmenu
) - see the creation date for the case (
showdatecreated
) - obtain an audit trail from within this listing (
showreport
) - use cases as templates for new cases (
showcopycase
)
{
"cases" : [
{"name" : STR,
"dateenter" : TIME,
"modelid" : INT,
"sessionid" : STR
}
],
"showdeleteinmenu" : true | false,
"showdatecreated" : true | false,
"showreport" : true | false,
"showcopycase" : true | false
}