The REST Entity service is an oData adapter
built on top of the SOAP based Entity service. This means that the transfer
protocols follow the oData conventions, while the business logic is similar to
the SOAP service. The REST Entity service supports both ATOM XML and JSON
payload formatting.
Examples will be given using the entity
Account, which is used to maintain associates of diferent types (customers,
suppliers, resellers) as well as track prospective customers in the various
stages of a sales cycle(suspect,->lead->prospect->customer). This
document will focus primarily on the markup of the request and response
payloads, as well as the structure of the request URI. Specialized procedures
like dealing with binary components of an entity (pictures, file attachments
and large texts), as well as dealing with header/line data (sales orders,
invoices, financial entries) will be outlined in separate documents that focus more
on the process.
Request markup
With all requests, the following
considerations for its markup are important.
·
Credentials: The Entity service itself runs
under a service account without authorization to any feature in Globe, and will
impersonate towards the credentials provided. These credentials should be
provided as NTLM network credentials and authenticate the client as a user that
exists in Globe as an active employee with sufficient function rights to
maintain the data that the client tries to maintain.
·
ContentType: application/atom+xml if the
request payload is formatted using ATOM markup. application/json if the
request payload is formatted using JSON markup. Not relevant for Retrieve and
Delete actions, since those do not require a content payload.
·
Accept: application/atom+xml,application/xml;
charset=utf-8 if the response payload should be formatted using ATOM
markup. application/json,text/javascript; charset=utf-8 if the response
payload should be formatted using JSON markup. Not relevant for Update and
Delete actions, which don’t return a content payload.
·
Method: POST for Create, GET for Retrieve/query,
MERGE for Update and DELETE for Delete.
On top of this standard markup, two custom
fields, which point to the database to be used, should be included in the
request header:
·
ServerName: needs to contain the network address
of the SQL server instance on which the database is located. This address
should be relative to the machine that hosts the Entity service.
·
DatabaseName: the name of the database under
which it is stored in SQL server. This should be the name in SQL itself. Not
the company number that is usually shown in Globe itself.
URI conventions
Within oData, there is an URI that points
to the entity as a whole, and one that points to a specific record within that
entity. This record specific URI includes the primary key for that entity, and
is used to retrieve the fields for that specific record, as well as to perform
Update and Delete actions. This URI is included in the response payload of Create
and Retrieve actions. The precise location depends on whether ATOM or JSON
markup is used.
The URI starts with the network address of
the service host, relative to the calling client application, followed by the
portnumber under which the REST service is running. This portnumber is stored
in the file Exact.WindowsService.config in the XMD folder of the Globe
installation on the service host, and is usually 8020.
The service location is /Services/Exact.Entity.REST.EG.
The full URI for the Account entity when calling the service locally would be:
http://localhost:8020/Services/Exact.Entity.REST.EG/Account
The URI to access a specific account within
this entity will be structured as follows (using customer 60089 in a McBean
demo company):
http://localhost:8020/services/Exact.Entity.REST.EG/Account(guid'e11c4af3-7fa9-4a61-9152-4a8b7743f911')
When retrieving data, a query expression
can be supplied through a set of parameters to both filter results and provide
input that affects the behavior of the retrieve action. This uses the following
URI parameters:
·
$top: limits the number of records returned in a
single response. If more records are to be returned, the subsequent records can
be retrieved by using a link in the response payload that is marked as next
(ATOM) or __next (JSON). If this parameter is missing, as many records will be
returned as what fits within the maximum allowed chunk size for the service, or
all records found, whichever is less.
·
$select: causes the service to only return those
properties that are mentioned by this parameter. If this parameter is missing,
all properties will be returned.
·
$orderby: determines the properties by which the
results are sorted within the response. If this parameter is missing, the
sorting method is however SQL returned the results to the service.
·
$filter: This parameter is used twofold. It can
be used to filter for only specific property values, but it is also used to
provide input to the service if this is needed (this is, for example used to
perform a retrieve that should include binary data, which by default is
omitted). If this parameter is missing, all records stored within this entity
will be recovered.
The $filter expression supports the
following operands:
·
eq: equal to
·
ne: not equal to
·
gt: greater than
·
ge: greater than or equal to
·
lt: lesser than
·
le: lesser than or equal to
This example retrieves the identity GUID
for account code 60089 (note that with right aligned fields leading spaces
should be included):
http://localhost:8020/Services/Exact.Entity.REST.EG/Account/?$top=1&$select=ID&$filter=AccountCode
eq ' 60089'
Entity payload
The Entity service uses a fragment of the
entity payload, as defined by the oData conventions for both up and download.
This format revolves around a collection of name-value pairs which list all
relevant properties and their values. In response payloads, either all
properties, or all properties specified by the $select URI parameter are
included. In request payloads, only those properties that are relevant should
be included. For Create actions this means all properties that are either
mandatory or for which a non default value should be used. For Update actions
this means all properties for which the value should be changed.
ATOM XML markup
The entity markup in the ATOM format is
largely the same for request and response. This is because it includes a lot of
mandatory overhead that while not actively used, is still required by the oData
serializer of the service. The format is as follows:
<?xml version="1.0"
encoding="utf-8" standalone="yes"?>
<entry
xmlns="http://www.w3.org/2005/Atom"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
<title/>
<summary/>
<updated>2015-06-11T08:15:57Z</updated>
<author>
<name/>
</author>
<category
scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"
term=Exact.Metadata.Entity.Account
<content
type="application/xml">
<m:properties>
<d:ID>e11c4af3-7fa9-4a61-9152-4a8b7743f911</d:ID>
.
.
</m:properties>
</content>
</entry>
Within a query result, multiple
<entry> nodes will be included within a <feed> node that
encapsulates them all. There will also be a <link rel=’next’> node that
contains the link to retrieve the next batch of results if not all results
could be returned in a single response. The date in the <updated> node
should be in the XML format for UTC date time notation. The term attribute for
the <category> node should be Exact.Metadata.Entity.EntityName, with
EntityName the name of the entity used.
JSON markup
The payload format for JSON is a lot more
compact, but this makes the differences between the request and response
markup, as well as the response markup for single and multiple records a bit
more pronounced. The request markup is simply a name-value pair collection for
every relevant property:
{
“AccountName”:”Restaurant Enkhuizen”,
“CurrencyCode”:”EUR”,
.
.
}
The name should be the property name as
exposed by that entity’s metadata. The value should be in the type appropriate
for that property, which is also described by the entity’s metadata.
The single record response markup is as
follows:
{
“d”:{
“__metadata”:{
"id":"http://localhost:8020/services/Exact.Entity.REST.EG/Account(guid'e11c4af3-7fa9-4a61-9152-4a8b7743f911')",
"uri":"http://localhost:8020/services/Exact.Entity.REST.EG/Account(guid'e11c4af3-7fa9-4a61-9152-4a8b7743f911')",
"type":"Exact.Metadata.Entity.Account"
},
“AccountName”:”Restaurant
Enkhuizen”,
“CurrencyCode”:”EUR”,
.
.
}
}
The name-value pair collection is in this
situation embedded in a collection named “d”, which also contains a metadata
element labeled “__metadata”. In this element, the most relevant element is
“id”, which contains the URI pointing to the record concerned.
The multiple record markup is as follows:
{
“d”:{
“results”:[
{
“__metadata”:{
…
},
“AccountName”:”Restaurant
Enkhuizen”,
.
.
},
{
“__metadata”:{
…
},
…
},
.
.
],
“__next”:”
http://localhost:8020/Services/Exact.Entity.REST.EG/Account/?$filter=ID%20eq%20guid'e11c4af3-7fa9-4a61-9152-4a8b7743f911'%20and%20IsBinaryServiceEnabled%20eq%20true&$top=1&$skiptoken=126L”
}
}
In this situation, the property collection,
along with the metadata element are put in an array with one element per
record. This array is put in a collection labelled “results”, which also
contains the element containing the URI to retrieve the next batch of records.
The results collection is put in the d collection.
CRUD action exchanges
Create
The request needs to be a POST to the
entity generic URI. The request payload needs to contain all properties that
are either mandatory, or for which you do not desire the value to be generated
by the business logic. The response payload will contain the entity as it has
been stored, along with the record specific URI for it.
Retrieve
The request needs to be a GET. It can
either be done to the record specific URI of a single record, or the generic
URI if you wish to perform a search or need to provide query criteria. All
input to the service is provided by the URI. There is no request payload. The
response payload will contain the data stored in the requested record (record
specific URI), or a set of property collections that match the provided
criteria, one collection per record (query on the entity generic URI).
Update
The request needs to be a MERGE on the
record specific URI of the record that you wish to update. The request payload
needs to contain all properties that you wish to change. There is no response
payload. If you wish to examine the data after updating it, you will need to
follow up your Update with a Retrieve.
Delete
The request needs to be a DELETE on the
record specific URI of the record that you wish to delete. This is all the
information that will be exchanged. There is neither a request nor a response
payload. If you get an OK or No content response, the Delete was successful.