Thursday, March 21, 2013

No API? No problem!

The Problem of Not Quite Having the API You Need...

Most discussion around APIs tends to focus on the provisioning of proxies for existing services, whether they be internal or cloud or SaaS based, and then managing these APIs. What happens when you have a business requirement for an API but you don't actually have an existing service that you can proxy?

It may be though that you have two or more backend services that you would like to combine into a single API or you might want to combine two or more cloud or SaaS services into a single API or a combination of both.

In the case of internal services it may simply not be expedient to create a brand new service to combine the various internal services and so need an alternative method to create this composite API.

In the case of combining multiple cloud or SaaS services into a single API it doesn't make a whole lot of sense to create a composite service on premise simply to serve this to a cloud based API Management solution. Much better to keep all that in the cloud.

Using the Assembly Capability in IBM API Management

IBM API Management provides both a proxy capability and the ability to create composite APIs using Assemblies. Assemblies provide a number of capabilities beyond the standard proxy:
  • Combine multiple services into a single API.
  • Map an existing service to a different message structure. This may be desirable when the existing service is complex and we'd like to simplify it without having to create a brand new service to proxy. Secondly we can always extend it later.
  • Perform more complex mapping and format translation to make the API more useful to consumers.
  • Call into SaaS offerings like Salesforce.
  • Connect directly to internal resources like databases.
  • Convert an XML based service into an API using JSON and vice versa.
All of these capabilities are provided as standard function within IBM API Management and allow for very flexible creation of APIs from a variety of sources and gives you a great degree of flexibility when you don't quite have the API that you need to expose.

Create an API Combining Two Existing Services

In this example we will create an example composite API using IBM API Management Assemblies.

We currently have two services:
  • Get product details.
  • Get product reviews.
We have a requirement from one of our customers to provide an API that combines the product detail with the reviews into a single response from a single request. Out IT department doesn't have the time to create the new service at the moment so we instead will use IBM API Management to perform the task.

Create the API and GET Resource

First we need to create the API itself. Log into Cast Iron Web API Management Web API Builder and add a new API, calling it "Get Products and Reviews" with a context of "products". Click "Create".


Click on the "Get Products and Reviews" link to edit the API. This will allow us to create the GET resource that we will use to build the API assembly.


We will use a single GET resource to call both backend services. On the "Resource Definition" tab add a new GET resource, name it "productAndReviews/{productId}" where the "productId" will be the parameter that we pass into the API. Finally, click "Add" to create the API resource.



Click on the "productAndReviews/{productId}" link to edit this new resource.


If we were simply doing a proxy API then we would select the "Proxy" checkbox but in this case we need to call multiple backend services and so a proxy is not appropriate. We will instead use the Assembly capability to create the API resource.


First we need to paste in a sample response message. This works as documentation for developers but also provides the mapping target inside the Assembly. We can paste in the following response JSON message into the "Response Body":

{
"product": {
"basePrice": 27.89,
"description": "A delicious biscuity aroma complemented with subtle wood and barrel ageing before bottling",
"imageURL": "http://images.gigamarkets.com/images/fullsize/4900133522843.jpg",
"measure": "750ml",
"name": "Bison Grove Blancs de Noirs NV",
"catID": "1077",
"productCategory": "Wines and Spirits",
"productID": "4900133522843",
"thumbnailURL": "http://images.gigamarkets.com/images/thumbnail/4900133522843.jpg"
},
"reviews": [
{
"productID": "4900133522843",
"review": "A fantastic wine. Goes surprisingly well with beef.",
"reviewDate": "2013-01-09T11:39:38Z",
"starRating": 5,
"username": "pavsmith",
"reviewID": "1358070591609"
},
{
"productID": "4900133522843",
"review": "Great value. Shows you that you can actually make wine out of Pinot Noir.",
"reviewDate": "2012-12-24T13:45:33Z",
"starRating": 4,
"username": "leandag",
"reviewID": "1358070591621"
}
]
}



Create the Assembly to Aggregate the Backend Services

Now we can move onto creating the actual Assembly. This is done by clicking on the "Implement Resource" tab.


The Assembly editor gives us a great degree of flexibility when it comes to creating APIs. Many of the features were listed earlier in this article. In this case we are going to call two existing services and aggregate their responses into a single response for the API.

The Get Product Service

To add the first service click on the large "plus" icon in the Assembly editor.


This brings up a palette of available targets including databases, salesforce.com and HTTP. In this case both of our backend services are provided by REST/JSON services so select a "GET Operation".


Our first task is to invoke the service to get product details. Change the name of the GET operation to "getProduct" both in the "HTTP GET operation" and in the name of the connection.

Also paste in the URL of the service, which in this case is:

https://rapid.web.castiron.com/catalogue/getProduct/{productID}?appId=5620f855-0104-44ee-8fdc-e33591e8b575

Finally click the "Connect" button. A connection will be made to the service to confirm that it is correct. Assuming this works you will automatically be forwarded to the "Define" tab where we configure the service specific information.


Give a useful description to both the "productID" and "appId" and then paste in a sample response message from the backend service into the "Response Body" section. Again this is partially for documentation purposes but it also provides the mapping source for when we aggregate the service responses later.

{
"basePrice": 34.12,
"catID": "1077",
"description": "A classic year with rich fruit underpinned by strong tannins and structure. Will last for decades!",
"imageURL": "http://images.gigamarkets.com/images/fullsize/4900133555764.jpg",
"measure": "750ml",
"name": "Big Penguins Reserve Shriaz 2007",
"productCategory": "Wines and Spirits",
"productID": "4900133555764",
"thumbnailURL": "http://images.gigamarkets.com/images/thumbnail/4900133555764.jpg"
}



We can now map the input parameters for this backend service. Click on the "Configure" tab. This allows us to define the content of the parameters required to call the service. In this case we need to provide a "productID" and an "appId". The product Id we will get from the input message for the API and the application Id is a hardcoded value.

To map the product Id click on "Select Available Value" next to "productID".


From the resulting popup select Request > Parameters > productId. This is the input parameter for the API resource that we are editing.


To enter the hardcoded application Id click on the icon at the far end of the "appId" row.


Enter the following application Id: 5620f855-0104-44ee-8fdc-e33591e8b575 and click "OK".


The icon will change to green to indicate that a value has been provided for that parameter.


We have now configured the product part of the API resource and can now move onto the reviews part.

The Get Product Reviews Service

Click on the "plus" icon again and add another HTTP GET operation.



Change the name of the GET operation to "getProducReviewst" both in the "HTTP GET operation" and in the name of the connection.

Also paste in the URL of the service, which in this case is:

https://rapid.web.castiron.com/catalogue/getProdReviews/{productID}?appId=5620f855-0104-44ee-8fdc-e33591e8b575

Finally click "Connect" to confirm that the backend service is reachable.



Again assuming the service is configured correctly you will automatically be moved to the "Define" tab. Add useful descriptions to the two parameters and paste a sample response into the "Response Body".

{
"reviews": [
{
"productID": "4900133522843",
"review": "A fantastic wine. Goes surprisingly well with beef.",
"reviewDate": "2013-01-09T11:39:38Z",
"starRating": 5,
"username": "pavsmith",
"reviewID": "1358070591609"
},
{
"productID": "4900133522843",
"review": "Great value. Shows you that you can actually make wine out of Pinot Noir.",
"reviewDate": "2012-12-24T13:45:33Z",
"starRating": 4,
"username": "leandag",
"reviewID": "1358070591621"
}
]
}



Again we need to map the input parameters for this service. Switch to the "Configure" tab.

As before click on "Select Available Value" for for the "productID" parameter and select Request > Parameters > productId from the popup.


To map the "appId" parameter click on the icon at the end of the parameter's row, enter 5620f855-0104-44ee-8fdc-e33591e8b575 and click "OK".


Map the Services Output Messages to the API Output Message

We have now completed the configuration required to call the two backend services. Now all that remains is to map the responses from the two backend services to the API resource response message. Click on "Response" to edit the required map.


Again we could use the same mapping facility of selecting available values that we used to map the input parameters above, but in this case we will be mapping a lot more fields and so we will switch to the drag and drop editor. Click on "Map Values".


This displays the mapping editor. On the left side you have all of the fields from the output messages of the two backend services that we have configured. On the right side we have the fields from the sample output message of our API resource.


Mapping is a simple act of dragging and dropping the relevant fields from the input to the output. In this case we are simply mapping fields directly and require no transformation. If you click on the "plus" icon on any of the wires you will see all of the potential transformation options that are available to you.

Once you have finished mapping all of the fields you have completed the configuration of our assembly!


Create an API Entitlement

The last thing we need to do before testing our new API is to define an Entitlement for the API. Click on the "Entitlements" tab.


Add a new entitlement called "Basic" with a maximum of 50 calls/minute, leaving all other options as default and click "Add".


Test the API

The API is now ready for testing. We now have to start the API resource. Return to the "Resource Definition" tab and click the "activate" icon next to your API resource and wait for the resource to activate.



Switch to the "Test" tab and select "GET productAndReviews{productId}" and the "Test Application" from the pulldowns.

Enter 4900133522843 as the "productId".

Click the "Test" button.


Assuming everything has been configured correctly you will see a valid response showing the combined product detail and reviews in a single response message!


Summary and Discussion

In this example we have shown the flexibility of using IBM API Management to go beyond simple proxying of backend services and instead create a new API aggregating two services.


This facility to call multiple services provides a highly flexible mechanism for integrating a number of disparate services from within and outside of the enterprise. It is also changeable over time. Services can be modified, removed, added and the order in which they are invoked can be changed as well. The mapping facility also allows us to use the output messages of previously invoked services in calling later services.

Another possibility is to use other APIs that you have created as source "services" in an Assembly, allowing you to combine your existing APIs with other services and APIs to create new and innovative APIs without necessarily needing to go back and change the existing APIs, which may affect existing consumers of those APIs.

The Assembly mechanism in IBM API Management provides a very high level of flexibility that allows the API author to create innovative APIs from existing services and APIs without needing to rely on other integration technologies and means they can define new APIs quickly to respond to business and customer needs.

Saturday, March 2, 2013

Create a Basic Proxy API

This post looks at the creation of a basic proxy API. It is the simplest kind of API where we simply proxy an existing service. The key reason that we want to do this is that we can use API management to register, track and control apps and app developers and the use of our API resources. A simple proxy API will be the most common use of APIs typically.

The Source REST Service

For the purposes of this test we will select a publicly available service that requires no additional registration or use of application keys. In this case we are going to use one of the public APIs provided by the BBC to get information about various programmes and schedules. The API is documented here:

BBC Programme Developers Page

It provides a set of information about schedules, genres and individual programmes. We will use this to get upcoming episodes of a particular programme.


Schedules

            /:service/programmes/schedules{/:outlet}
            /:service/programmes/schedules{/:outlet}/:year/:month/:day
            /:service/programmes/schedules{/:outlet}/:year/:month/:day/ataglance
            /:service/programmes/schedules{/:outlet}/yesterday
            /:service/programmes/schedules{/:outlet}/today
            /:service/programmes/schedules{/:outlet}/tomorrow
        

Genres

            {/:service}/programmes/genres/:genre1{/:genre2{/:genre3}}/schedules
            {/:service}/programmes/genres/:genre1{/:genre2{/:genre3}}/schedules/:year/:month/:day
            {/:service}/programmes/genres/:genre1{/:genre2{/:genre3}}/schedules/:year/:month/:day/ataglance
            {/:service}/programmes/genres/:genre1{/:genre2{/:genre3}}/schedules/upcoming
        

Programmes

            /programmes/:groupPID/episodes/upcoming
            /programmes/:groupPID/episodes/upcoming/debut
            /programmes/:groupPID/episodes/player


The API follows exactly the same URL model as the BBC website. So, if we want to look at upcoming episodes of Saturday Kitchen we simply need to use a browser to get to the programme's website. The programme's id is contained within the link.


To help our eventual app developers we need to get some sample JSON output from the REST service. To do this we simply use the "upcoming" method. We can paste the following link into a browser.

http://www.bbc.co.uk/programmes/b006v5y2/episodes/upcoming.json

Copy and paste the output message into a text editor as we will need it soon when we create the API.



Create and Test the API

We can now create our API. Log into the Cast Iron Web API Builder at:

https://webapi.castiron.com/webapibuilder

Create a new API called "BBC Programmes API", give it a context of "bbcProgrammes", add a description and click "Create".


Click on the "BBC Programmes API" link to edit the API.


Add a "GET" resource with a URI of: programmes/{programmeId}/episodes/upcoming.json


Click on the link to edit the API resource.


Select the "Proxy" checkbox and enter the following address for the proxy:

http://www.bbc.co.uk/programmes/

Note that API Management will match the URI up to "/programmes/" and append the remainder of the URI from the API resource.


Paste in the sample JSON response that you saved earlier. Note that when you paste in the message the JSON will be formatted assuming the JSON is valid. If it is invalid the JSON will not format nicely and the response body section will be shaded red to indicate the error.

 

The basic API is now complete but we need to do one more thing before we can test. We need to add at least one entitlement to the API. Return to the main API page and click on the "Entitlements" tab.
Add an entitlement called "Basic Entitlement" and give it a description and a number of calls per minute and click "Add".


The API is mow complete and we can test it. Return to the "Resource Definition" tab and activate the resource by clicking on the Activate icon. Click "OK" once the resource activates successfully.

 

Click on the "Test" tab, select the GET resource and the "Test Application". Paste the programme id into the "programmeId" parameter and then click "Test".


After a moment you should see a successful response from the service.

 

That completes the creation of a basic proxy API.