This article provides instructions on creating a resource that will be represented by a JSON object. Resources that need to be represented in other formats will be other articles. This article will also focus on creating a resource based on a database table. Since the SRP HTTP Framework ships with a sample CONTACTS database table, we'll use it for our demonstration purposes. All of our examples will assume the following API is being called:
GET /contacts/1
Resources that are not based on data in a table can still use some of the principles presented below, but there will need to be a little more effort. We will provide additional articles to demonstrate how non-database resources can be created.
We've already explained that a resource can be represented in any digital format, but the conventional format used by RESTful APIs is to use JSON. In our documentation we will often make reference to the resource object, which is short-hand for the "resource as represented by a serialized JSON object".
There are four basic methods for creating a resource within the SRP HTTP Framework. You will choose the method that best suits your needs. We will list the pros and cons of each method and provide sample code that creates the same resource using each method.
For simple database related resources, the GetDatabaseItem service (a member of the HTTP_Resource_Services module) can be used with minimal code. Just get the Key ID from the prepopulated EndpointSegment variable and pass in the name of the database table:
API contacts.ID.GET KeyID = EndpointSegment HTTP_Resource_Services('GetDatabaseItem', 'CONTACTS', '', KeyID) end api |
This produces the following resource object:
{ "address":"6649 N Blue Gum St", "birthdate":"", "city":"New Orleans", "company":"Benton, John B Jr", "county":"Orleans", "email":"jbutt@gmail.com", "first_name":"James", "last_name":"Butt", "notes":"", "picture":"\\WebAppData\\ContactPictures\\1.jpeg", "state":"LA", "url":"http://www.bentonjohnbjr.com", "zip":"70116", "phone":[ { "phone_number":"(504) 621-8927", "phone_type":"Phone 1" }, { "phone_number":"(504) 845-1427", "phone_type":"Phone 2" } ] } |
One of the drawbacks of calling the GetDatabaseItem service is that property names are formatted with underscores (i.e., how they appear in the dictionary) rather than as camel case (which is the conventional format for JSON objects). Another drawback is that the GetDatabaseItem service attempts to create a resource object from all column data (both physical and calculated). This might be undesirable if some of the data is meaningless to the client. Consider the picture property in the above resource object. It references an image file stored locally on the server, which has no value to the client. This can also be problematic if a calculated column encounters a runtime error or is dependent upon information that only exists within an OpenInsight desktop session. To resolve both of the above items, we will take advantage of the optional ColumnNames and ItemArrayLabel arguments. To keep our sample code simple and concise, we will limit our resource to just the FIRST_NAME, LAST_NAME, ADDRESS, CITY, STATE, and ZIP database columns:
API contacts.ID.GET KeyID = EndpointSegment ColumnNames = 'FIRST_NAME' : @FM : 'LAST_NAME' : @FM : 'ADDRESS' : @FM : 'CITY' : @FM : 'STATE' : @FM : 'ZIP' ItemArrayLabel = 'firstName' : @FM : 'lastName' : @FM : 'address' : @FM : 'city' : @FM : 'state' : @FM : 'zipCode' HTTP_Resource_Services('GetDatabaseItem', 'CONTACTS', '', KeyID, ColumnNames, ItemArrayLabel) end api |
Our resource object now appears like this:
{ "address": "6649 N Blue Gum St", "city": "New Orleans", "firstName": "James", "lastName": "Butt", "state": "LA", "zipCode": "70116" } |
Pros:
Cons:
GetDatabaseItem is an example of a high-level service. That is, it relies upon a simple interface and default behavior. Like other high-level services, GetDatabaseItem is built on top of slightly lower-level services. The most important one of these is GetObject. (which is also a member of the HTTP_Resource_Services module). Let's look at an example of an API that uses the GetObject service to produce the same resource as the GetDatabaseItem service:
API contacts.ID.GET KeyID = EndpointSegment ColumnNames = 'FIRST_NAME' : @FM : 'LAST_NAME' : @FM : 'ADDRESS' : @FM : 'CITY' : @FM : 'STATE' : @FM : 'ZIP' PropertyNames = 'firstName' : @FM : 'lastName' : @FM : 'address' : @FM : 'city' : @FM : 'state' : @FM : 'zipCode' // Create a JSON object in memory. objResource = HTTP_Resource_Services('GetObject', 'CONTACTS', KeyID, ColumnNames, PropertyNames) If Error_Services('NoError') then // Serialize the JSON object. jsonResource = HTTP_Resource_Services('GetSerializedResource', objResource) // Set the response body with the serialized JSON object and set the Content-Type response header. HTTP_Services('SetResponseBody', jsonResource, False$, 'application/hal+json') end else // There is an error condition so call the SetResponseError service. HTTP_Services('SetResponseError', '', '', 500, Error_Services('GetMessage'), FullEndpointURL) end end api |
In many ways, GetObject and GetDatabaseItem are the same, including sharing many of the same arguments. GetObects differs from GetDatabaseItem in the following ways:
Since GetObject only returns a handle to the JSON object, it is the responsibility of the calling process to serialize the resource and update the HTTP response (e.g., Body, Content-Type Header, Status Code, etc.). The reason developers might choose to work with the GetObject service instead of the GetDatabaseItem service (aside from the latter being deprecated) is because developers might require a little more control and ability to customize the resource object. For this reason, developers have access to several other useful services such as AddProperty, AddSubProperty, AddSubResource, AddLInkRelationship, AddEmbeddedResources, and AddFormAction.
Pros:
Cons: