Using an API with OpenAPI Spec

An API with an OpenAPI 3.0 spec can be used to generate an AIMMS Library. This AIMMS Library can subsequently be used to ease interfacing the corresponding service significantly.

This article illustrates interfacing a service with an OpenAPI 3.0 specification. As you know the following architecture is provided:

../../_images/client-server-openapi-lib1.png

The translation of AIMMS data to the format accepted by the server (arrow 2), and translating the response provided by the server into AIMMS data (arrow 3) are taken care of by a generated AIMMS library.

The purpose of this article is to illustrate:

  1. initialization of an OpenAPI generated AIMMS library,

  2. make a request to such a library (arrow 1), and

  3. handle a response from such a library (arrow 4).

However, to make this concrete, an example is used, which is presented here. This example illustrates a IP Locator. Note that to work with this example you will need an API key, from https://iptwist.com/settings.

../../_images/tokyo.png

Preparation

The preparations needed come prepackaged in the LibraryInitialization routine of the OpenAPI generated library openapi-ipTwist:

 1! Read mapping files for this library.
 2block
 3    DirectoryOfLibraryProject("openapi_ipTwist", libFolder);
 4onerror err do
 5    libFolder := "../libs/openapi-ipTwist/";
 6    errh::MarkAsHandled(err);
 7endblock;
 8dex::ReadMappings(libFolder, "Generated/openapi-ipTwist", 0);
 9
10! Read server initialization data (e.g. service URL, API key, OAuth credentials)
11apiInitFile := "../api-init/openapi-ipTwist.txt";
12if FileExists(apiInitFile) then
13    read from file apiInitFile;
14endif ;

Selected remarks about this code:

  • Lines 1-8: The mapping files are in the subfolder ./Mappings/Generated/openapi-ipTwist of the library folder.

  • Lines 10-14: Read in ipTwist config information, such as server name and API Key.

Example contents for the openapi-ipTwist.txt are as follows:

1ipTwist::api::APIServer :=  "https://iptwist.com" ;
2ipTwist::api::APIKey('X-IPTWIST-TOKEN') := "" ;

There is one server for the service ipTwist, namely ipTwist.com; so the server is specified in the initialization file. Of course, you can choose to enter your API key directly in this file.

Calling the API

Using the openapi_ipTwist library, making a request is just as follows:

 1! Starting current call.
 2ipTwist::api::NewCallInstance(ep_callInstance);
 3
 4! Fill in the data for making the request.
 5ipTwist::_Request::ip(ep_callInstance) := sp_myIPAddress ;
 6
 7! Install hook, which will copy the data or handle the error
 8ipTwist::api::post_::UserResponseHook :=
 9    'pr_GeolocateResponseHook' ;
10
11! Start the request.
12ipTwist::api::post_::apiCall(ep_callInstance);

Remarks:

  1. Line 2: Each request is an object. The value of this mechanism will be illustrated in another how-to.

  2. Line 5: Here the data of the application is actually copied to the parameters of the openapi_ipTwist library. Highlighted, as this part requires application specific logic.

  3. Line 8: The library needs to know which procedure should handle the response (arrow 4).

  4. Line 11: Actually starting the request.

  5. At ipTwist example, this procedure is called pr_GeolocateMakeRequest.

Handling the Response

Using the openapi_ipTwist library, handling the response is just as follows:

 1switch ipTwist::api::CallStatusCode(ep_callInstance) do
 2
 3    '200':
 4        block ! Success, copy data retrieved to application core data structures.
 5            sp_city         := ipTwist::_Response::city(        ep_callInstance);
 6            sp_country      := ipTwist::_Response::country(     ep_callInstance);
 7            sp_countryCode  := ipTwist::_Response::country_code(ep_callInstance);
 8            p_lat           := ipTwist::_Response::latitude(    ep_callInstance);
 9            p_lon           := ipTwist::_Response::longitude(   ep_callInstance);
10            sp_state        := ipTwist::_Response::state(       ep_callInstance);
11            sp_timezone     := ipTwist::_Response::timezone_(   ep_callInstance);
12            sp_zip          := ipTwist::_Response::zip(         ep_callInstance);
13        endblock ;
14        ipTwist::_Response::EmptyInstance(ep_callInstance);
15        block ! Use data in core data structures for presentation purposes.
16            p_shownLocLatitude(  ep_ipLoc ) := p_lat ;
17            p_shownLocLongitude( ep_ipLoc ) := p_lon ;
18        endblock ;
19
20    '400','401','402','403','404','405','406','407','408','409','410','411','412','413','414','415','416','417','421','422','423','424','425','426','427','428','429','431','451',
21    '500','501','502','503','504','505','506','507','508','510','511':
22        raise error formatString("ipTwist::Geolocate(%s) failed (instance: \'%e\', status: %e, error: %e): %s",
23            sp_myIPAddress, ep_callInstance,
24            openapi_ipTwist::api::CallStatusCode(ep_callInstance),
25            openapi_ipTwist::api::CallErrorCode(ep_callInstance),
26            fnc_errorFunc( ipTwist::api::CallStatusCode(ep_callInstance) ) );
27
28    default:
29        raise error formatString("ipTwist::Geolocate(%s) failed (instance: \'%e\', status: %e, error: %e): %s",
30            sp_myIPAddress, ep_callInstance,
31            openapi_ipTwist::api::CallStatusCode(ep_callInstance),
32            openapi_ipTwist::api::CallErrorCode(ep_callInstance),
33            "unknown reason" );
34
35endswitch ;

Remarks:

  1. Lines 6-12: This is where the application logic comes in again. Here we copy the data from the openapi_ipTwist library into the data structures of the application.

  2. Line 14: After the data is retrieved as needed, the data can be removed from the OpenAPI library.

  3. Lines 16, 17: Use the data now in the core of the app.

  4. Lines 20-26, and 28-33: try to be nice to the end-user by sharing information about a failure. By sharing both what the response tries to handle (context information), and the cause of failure provided by the service, you will increase the chance that the user is able to handle the failure self, or find the proper point of contact directly.

  5. Line 26: The service provided by ipTwist does not provide a schema for error messages. Instead, its OpenAPI spec documents how to handle status codes in case of failure. This is why a separate function is built to translate documented status code to explanations.

  6. At ipTwist example, this procedure is called pr_GeolocateResponseHook.

Further information: