Skip to main content
Skip table of contents

Model Services - REST

In this lesson, you will learn about Model Services.  This is the automatic REST interface to the business model. First read about the details of how to make requests to Model Services, then we will do some activities.

Model Services Syntax

Documentation for the JSON version of the REST interface may be accessed at <serverRoot>/openAPI.html. It also gives you the opportunity to try it out. For example: http://localhost:7080/training/openAPI.html.

Model Services provide API access to the Business Model for REST style create, read, update, delete, and invoke.  They are available at <serverRoot>/<format>/<objectType>/<id>?<parameters> along with an HTTP Method to indicate the CRUD (create, read, update, delete) verb.

If you don't specify an "attributes" parameter, all public primitive attributes are returned.

If you do specify a list of primitive attributes in the attributes parameter, then only those attributes will be returned.

e.g. (firstName lastName)

Associated objects can be retrieved using nested lists in the attributes parameter. Simply specify a non-primitive attribute name then a list of one or more attributes. For example:

firstName lastName (addrs city state zip))

These nestings can continue. For example:

(firstName lastName (addrs city state zip (type name)))

Attributes can also be retrieved polymorphically - meaning attributes that only exist on subclasses can be retrieved when reading the base class. (see examples below)

Attribute names in the where and order by parameters may take the simple form <attributeName> or alternatively (@ <attributeName>). The second form is recommended. In this case, the "@" represents the current instance and may be used to traverse arbitrarily long association paths. For example, on User we may specify:


(= (@ person homeAddress city) "Toronto")

Example response
[{
      "$class": "Person",
      "$oid": "10031C7A7EF46D45ADBC72090BCCD04825",
      "lastName": "Cotherman",
      "addrs": [
         {
            "$class": "Address",
            "$oid": "10EE388953279847C6B7DB63CACAB774C0",
            "state": null,
            "zip": null,
            "type": {
               "$class": "AddressType",
               "$oid": "1000000000000010008000CEEDED004000",
               "name": "Business"
            },
            "city": null
         }
      ],
      "firstName": "Joseph",
      "initials": null
   }

]

$class and $oid

The $class and $oid attributes of an object are always returned.

They are the class name of the object and unique identifier respectively.

Request Structure

Model Services are available at <serverRoot>/<format>/<objectType>/<id>?<parameters> along with an HTTP Method to indicate the CRUD verb.  

serverRoot 

The host and context root of the server. For example: http://localhost:7080/training.

This is defined in your environment file.

format 

Defines the return type for the request.  Formats supported include "json", "xml", and "web" for a SOAP encoding. These endpoints support the REST style requests discussed here. We use the json format for all of the examples in this document.  To see the effect of another protocol, simply replace json with xml or web in the examples. Additionally, there are other supported protocols including soap and text but they use a different API style called Generic RPC and are not discussed here.  

objectType 

Specifies the object type to work on e.g. Person, Household, or Account

id 

An optional unique identifier for the item to work on.  If there is no id in the URL, the request will work on a collection, if there is one, it will work on a specific instance. For example: http://localhost:7080/training/json/Person/101DBCCB4F0B4E4345BDD1C68ECE20DBBD?$indent.

parameters

The parameters, attributes, where, orderby, count and offset, employ the same syntax as with any object query (in other words, the same syntax used in scripting for reads).

$indent 

Pretty print the output.

We include the $indent parameter in many of the following examples. It is only for readability and is not required.

attributes

The list of attributes, or associated objects, to proactively retrieve. To retrieve all primitive attributes, leave this parameter out.  To retrieve selected primitive attributes or just the id of associated objects, list them in the brackets. For example: http://localhost:7080/training/json/Person?attributes=(firstName lastName initials addrs)&$indent.

To traverse association paths you can wrap associated objects in brackets then list their primitive and associated attributes.  This can be done recursively as seen here. For example: http://localhost:7080/training/json/Person?attributes=(firstName lastName initials (addrs city state zip (type name)))&$indent.

Example response
{
      "$class": "Person",
      "$oid": "10031C7A7EF46D45ADBC72090BCCD04825",
      "lastName": "Cotherman",
      "addrs": [
         {
            "$class": "Address",
            "$oid": "10EE388953279847C6B7DB63CACAB774C0",
            "state": null,
            "zip": null,
            "type": {
               "$class": "AddressType",
               "$oid": "1000000000000010008000CEEDED004000",
               "name": "Business"
            },
            "city": null
         }
      ],
      "firstName": "Joseph",
      "initials": null
   },


Two special (read advanced (smile)) syntax exist for downcast and annotations. 

Attribute downcast syntax (@@) - Polymorphic read is used to proactively load subclass specific attributes when reading from a base class.  In the following example we only retrieve the homePhone attribute for Entity records that are of type Person, otherwise we don't include it.

http://localhost:7080/training/json/Entity?attributes=(fullName lastName (@@ Person firstName homePhone))&$indent

Annotations syntax - create calculated attributes on-the-fly

In this example, return the lastName attribute, a calculated _lnLen attribute which is the length of the last name, and a _fullName calculated attribute.  We use the underscore here just to avoid name collisions. For example:

http://localhost:7080/training/json/Person?attributes=(lastName (: _lnLen (string-length (@ lastName))) (: _fullName (string-append (@ lastName) (@ firstName))))&$indent

Aggregate functions - can be applied to subcollections on instances. Supported operators include count, average, min, max, sum. For example:

http://localhost:7080/training/json/Person?attributes=(firstName lastName (: _countryCnt (count (@ addrs country))) (: _uniqueCountryCnt (count (unique (@ addrs country)))) (: _nullCodeCnt (count (null? (@ addrs zip)))) (: _avg (average (string-length (@ addrs city)))) (: _min (minimum (string-length (@ addrs city)))) (: _max (maximum (@ addrs city))) (: _sum (sum (string-length (@ addrs city)))))&$indent

where

The where clause. The following examples illustrate the use of associations, reverse associations and qualified associations.

Simple where not using the @ syntax - (and ( = firstName "Tim") (= lastName "Lamont"))

Simple where using the @ syntax - (and ( = (@ firstName) "Joe") (= (@ lastName) "Test"))

Any operator - Reduces the multiplicity of an association to 1 

Expressing queries that are impossible to do only with joins. In this example, return people who have at least one address in Toronto and at least one in Richmond Hill. Nothing will be returned by the equals operator equivalent (and (= (@ addrs city) "Toronto") (= (@ addrs city) "Richmond Hill"))

(and (any (= (@ addrs city) "Toronto")) (any (= (@ addrs city) "Richmond Hill"))) ; two part association path

Optimizing database filtering on collection associations. In this example, the database will return only one person record per matching addresses vs returning as many copies of a person record as there are matching addresses when using the equals operator equivalent (Person'read ... '(= (@ addrs city) "Toronto") ...)

(any (= (@ addrs city) "Toronto") ; two part association path

Conditions in where clause association paths.  This syntax allows us to restrict parts of association paths to specific subclasses and also to apply arbitrary conditions on association paths.

The most common use case: limit an association based on a qualifier e.g. look for all Entities with a user named "Shaw" playing their advisor role

(= (@ coverage (= (@ coverageRole roleName) "Advisor") userPerson lastName) "Shaw")

Subclass restriction example: note that homeAddress is an attribute that is only found on the Person subclass of Entity

(= (@ entity (instance? (@) Person) homeAddress city) "Toronto")

Arbitrary condition example: reads all instances of the Telcom class that has an entity with a lastname of "Shaw" that has an address in "Toronto" with and address2 line that is not null.

(not (null? (@ entity (= (@ lastName) "Shaw") addrs (= (@ city) "Toronto") address2)))

Note

Conditions may be applied in reverse associations as well as forward associations

Reverse association syntax (@@).  Used to query from the end of an association "back" to the class you are reading.  Forward associations take the form (@ part1 part2 part3 ...). The @ represents an instance of the class being read. Revese associations take the form (@@ <ClassName> part3 part2 part1) where part1 represents an attribute with a type of the class being read. You can usually just navigate the forward association, but you may see this syntax if you are tracing requests from NexJ UI clients.

Address?where=(= (@@ User person addrs) <userId>)

orderBy

The expressions on which to order the collection - a list of (<sort-expr> . <ascending?>) pairs.

E.g. (((@ firstName) . #t) ((@ lastName) . #f)) or more simply (since it is a single associate path length) ((firstName . #t) (lastName . #f)) 

count

The number of instances to retrieve. Null '() for the default value of -1, meaning up to the readLimit specified in the data source.  One cannot pass in a larger count than readLimit defined in the data source.

offset

The number of top level instances to skip from the beginning of the retrieved collection. Default value of 0.

HTTP Method

Maps as follows.  GET=read, POST=create or invoke, PUT=update, DELETE=delete

Body

The body of the request when creating, updating, or optionally deleting is an object structure similar to that returned during a read (or GET).


Try it out

Let's start by looking at the Open API documentation for Model Services. Navigate to http://localhost:7080/training/openAPI.html. You should get a response something like...

If we expand the GET /Person section, we will see that get supports the following querystring parameters.

At the top of the parameters section, press the 

button.

In the attributes textbox, enter (firstName lastName (addrs city state zip)) and in the count textbox enter 3.

Then press the blue Execute button at the bottom of the parameters section. That will execute the request against the server and return the result in the Response body section.

The request URL is http://localhost:7080/training/json/Person?attributes=(firstName%20lastName%20(addrs%20city%20state%20zip))&count=3.

Try out some of the other get parameters in your browser i.e. attributes, where, orderBy, count, and offset.  You will also want to put &$indent in the URL as well so your output is more readable.

You can try out some of the other methods (POST, DELETE, PUT) by installing Postman and trying it out.


JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.