Saturday, February 20, 2016

API Manager new REST API - From API Creator to Consumer

In this blog we will go through the basic steps of

1. Accessing Publisher REST API
2. Creating an API
3. Publishing an API
4. Accessing Store REST API
5. Creating an Application
6. Generate access token to that application
7. Subscribing to the API using the application
8. Invoking the API

using the new REST API.

Accessing Publisher web app

The new REST API is secured using OAuth so we need to give an access token when invoking APIs. The access tokens are created on behalf of an OAuth application. So first of all we need to create an OAuth application using the DCR endpoint to if you have not already done. Please see my previous blog post for more details about it. So I am going through those steps in brief.

Creating an OAuth application using DCR endpoint:

curl -X POST -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -d @payload.json http://localhost:9763/client-registration/v0.9/register

Sample payload.json file:
{
 "callbackUrl": "www.google.lk",
 "clientName": "rest_api_publisher",
 "tokenScope": "Production",
 "owner": "admin",
 "grantType": "password refresh_token",
 "saasApp": true
}

Response:
HTTP/1.1 201 Created
Date: Sun, 20 Mar 2016 03:29:57 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Server: WSO2 Carbon Server

{  
   "jsonString":"{\"username\":\"admin\",\"redirect_uris\":\"www.google.lk\",\"client_name\":\"admin_rest_api_publisher\",\"grant_types\":\"urn:ietf:params:oauth:grant-type:saml2-bearer iwa:ntlm implicit refresh_token client_credentials authorization_code password\"}",
   "appOwner":null,
   "clientName":null,
   "callBackURL":"www.google.lk",
   "isSaasApplication":true,
   "clientId":"xe94b1qreLVlplHjZGwLtfrmv38a",
   "clientSecret":"fOua2cfsdTowN0apzCcJ2uIfLMYa"
}
Extract the clientId and clientSecret from above response and use it to invoke the token endpoint. You have to base64 encode clientIt:clientSecret pair and use it as the Authorization: Basic header in the next step.

Get an access token using token endpoint:

In order to create an API, you need to have apim:api_create scope. So make sure you include the apim:api_create scope in your scope parameter. Here I am requesting all scopes related to API creator and publisher

curl -k -d "grant_type=password&username=admin&password=admin&scope=apim:api_create" -H "Authorization: Basic eGU5NGIxcXJlTFZscGxIalpHd0x0ZnJtdjM4YTpmT3VhMmNmc2RUb3dOMGFwekNjSjJ1SWZMTVlh" https://127.0.0.1:8243/token -v

Reponse:
< HTTP/1.1 200 OK
< Content-Type: application/json
< Pragma: no-cache
< Cache-Control: no-store
< Date: Sun, 20 Mar 2016 15:17:15 GMT
< Transfer-Encoding: chunked
< 
* Connection #0 to host 127.0.0.1 left intact
{"scope":"apim:api_create","token_type":"Bearer","expires_in":3600,"refresh_token":"fc6f5cc8fed59ca16acfd8ace97e3861","access_token":"a651175508fafcd116488d84e53ca3de"}

Note the access token a651175508fafcd116488d84e53ca3de which we will use for our next API requests.

Creating an API

Using the access token you can now invoke the API Create API. I will refer the sample payload added in the official documentation.

curl -H "Authorization: Bearer 8f1795f3d5d9c3b4d9bbeafd2e39f437" -H "Content-Type: application/json" -X POST -d @payload.json http://127.0.0.1:9763/api/am/publisher/v0.9/apis

Sample payload.json
{
"sequences": [],
"tiers": [
        "Unlimited"
    ],
"thumbnailUrl": "/registry/resource/_system/governance/apimgt/applicationdata/icons/admin/CalculatorAPI/1.0/icon",
"visibility": "PUBLIC",
"visibleRoles": [],
"visibleTenants": [],
"cacheTimeout": 300,
"endpointConfig": "{\"production_endpoints\": {\"url\": \"https://localhost:9443/am/sample/calculator/v1/api\",\"config\": null},\"sandbox_endpoints\": {\"url\": \"https://localhost:9443/am/sample/calculator/v1/api\",\"config\": null},\"endpoint_type\": \"http\" }",
"subscriptionAvailability": null,
"subscriptionAvailableTenants": [],
"destinationStatsEnabled": "Disabled",
"apiDefinition": "{\"basePath\":\"\\/calc\\/1.0\",\"host\":\"https:\\/\\/localhost:9443\",\"paths\":{\"\\/divide\":{\"get\":{\"x-auth-type\":\"Application & Application User\",\"summary\":\"divide x by y\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"type\":\"string\",\"required\":true,\"in\":\"query\"},{\"name\":\"y\",\"type\":\"string\",\"required\":true,\"in\":\"query\"}],\"responses\":{\"200\":{}}}},\"\\/subtract\":{\"get\":{\"x-auth-type\":\"Application & Application User\",\"summary\":\"subtract y from x\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"type\":\"string\",\"required\":true,\"in\":\"query\"},{\"name\":\"y\",\"type\":\"string\",\"required\":true,\"in\":\"query\"}],\"responses\":{\"200\":{}}}},\"\\/add\":{\"get\":{\"x-auth-type\":\"Application & Application User\",\"summary\":\"add x and y\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"type\":\"string\",\"required\":true,\"in\":\"query\"},{\"name\":\"y\",\"type\":\"string\",\"required\":true,\"in\":\"query\"}],\"responses\":{\"200\":{}}}},\"\\/multiply\":{\"get\":{\"x-auth-type\":\"Application & Application User\",\"summary\":\"multiply x by y\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"type\":\"string\",\"required\":true,\"in\":\"query\"},{\"name\":\"y\",\"type\":\"string\",\"required\":true,\"in\":\"query\"}],\"responses\":{\"200\":{}}}}},\"swagger\":\"2.0\",\"info\":{\"title\":\"Calculator\",\"description\":\"Simple calculator API to perform addition, subtraction, multiplication and division.\",\"version\":\"1.0\"}}",
"responseCaching": "Disabled",
"isDefaultVersion": false,
"gatewayEnvironments": "Production and Sandbox",
"businessInformation": {
"technicalOwner": null,
"technicalOwnerEmail": null,
"businessOwner": null,
"businessOwnerEmail": null
},
"transport": [
"http",
"https"
],
"tags": [
"calculator"
],
"provider": "admin",
"version": "1.0",
"name": "CalculatorSampleAPI",
"context": "/samplecalc",
"description": "Simple calculator API to perform addition, subtraction, multiplication and division."
}

Response:
< HTTP/1.1 201 Created
< Location: http://localhost:9763/api/am/publisher/v0.9/apis/96758d8d-b121-4ae9-a752-76d138295f3e
< Date: Sat, 26 Mar 2016 07:51:47 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Server: WSO2 Carbon Server
{
 "sequences": [],
 "tiers": ["Unlimited"],
 "thumbnailUrl": null,
 "visibility": "PUBLIC",
 "visibleRoles": [],
 "visibleTenants": [],
 "cacheTimeout": 300,
 "endpointConfig": "{\"production_endpoints\": {\"url\": \"https://localhost:9443/am/sample/calculator/v1/api\",\"config\": null},\"sandbox_endpoints\": {\"url\": \"https://localhost:9443/am/sample/calculator/v1/api\",\"config\": null},\"endpoint_type\": \"http\" }",
 "subscriptionAvailability": null,
 "subscriptionAvailableTenants": [],
 "destinationStatsEnabled": "Disabled",
 "apiDefinition": "{\"basePath\":\"\\/calc\\/1.0\",\"paths\":{\"\\/divide\":{\"get\":{\"summary\":\"divide x by y\",\"x-auth-type\":\"Application & Application User\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"required\":true,\"type\":\"string\",\"in\":\"query\"},{\"name\":\"y\",\"required\":true,\"type\":\"string\",\"in\":\"query\"}],\"responses\":{\"200\":{}}}},\"\\/subtract\":{\"get\":{\"summary\":\"subtract y from x\",\"x-auth-type\":\"Application & Application User\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"required\":true,\"type\":\"string\",\"in\":\"query\"},{\"name\":\"y\",\"required\":true,\"type\":\"string\",\"in\":\"query\"}],\"responses\":{\"200\":{}}}},\"\\/add\":{\"get\":{\"summary\":\"add x and y\",\"x-auth-type\":\"Application & Application User\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"required\":true,\"type\":\"string\",\"in\":\"query\"},{\"name\":\"y\",\"required\":true,\"type\":\"string\",\"in\":\"query\"}],\"responses\":{\"200\":{}}}},\"\\/multiply\":{\"get\":{\"summary\":\"multiply x by y\",\"x-auth-type\":\"Application & Application User\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"required\":true,\"type\":\"string\",\"in\":\"query\"},{\"name\":\"y\",\"required\":true,\"type\":\"string\",\"in\":\"query\"}],\"responses\":{\"200\":{}}}}},\"host\":\"https:\\/\\/localhost:9443\",\"swagger\":\"2.0\",\"info\":{\"title\":\"Calculator\",\"description\":\"Simple calculator API to perform addition, subtraction, multiplication and division.\",\"version\":\"1.0\"}}",
 "responseCaching": "Disabled",
 "isDefaultVersion": false,
 "gatewayEnvironments": "Production and Sandbox",
 "businessInformation": {
  "technicalOwner": null,
  "technicalOwnerEmail": null,
  "businessOwner": null,
  "businessOwnerEmail": null
 },
 "transport": ["http", "https"],
 "tags": ["calculator"],
 "provider": "admin",
 "version": "1.0",
 "name": "CalculatorSampleAPI",
 "context": "/samplecalc",
 "id": "96758d8d-b121-4ae9-a752-76d138295f3e",
 "description": "Simple calculator API to perform addition, subtraction, multiplication and division.",
 "status": "CREATED"
}
So we have created an API successfully.
There are few things to note.

The first one; what does it actually give it as a response? Is it same as the payload we specify when creating an API?.
You would be able to see few additional parameters in the response which you did not specify in your request.The "Id" parameter, that is the most important one. It is a UUID which uniquely identifies the API you created. When you need to refer to this API when retrieving it/ deleting it later, you can use this id.

The second one; the Location header. Did you notice you also received a Location header as a response. Let's double check once.
That is the path the new API resource is created. You can directly use it when retrieving the API.

Get a token for apim:api_view scope:
curl -k -d "grant_type=password&username=admin&password=admin&scope=apim:api_view" -H "Authorization: Basic eGU5NGIxcXJlTFZscGxIalpHd0x0ZnJtdjM4YTpmT3VhMmNmc2RUb3dOMGFwekNjSjJ1SWZMTVlh" https://127.0.0.1:8243/token -v
Response:
{"scope":"apim:api_view","token_type":"Bearer","expires_in":3600,"refresh_token":"11cc2f0283eed21b4407bab4d9a23e8c","access_token":"62692e79399d8f08b0cde3df70989b3d"}
Invoke:
curl -H "Authorization: Bearer 62692e79399d8f08b0cde3df70989b3d" -H "Content-Type: application/json" http://localhost:9763/api/am/publisher/v0.9/apis/96758d8d-b121-4ae9-a752-76d138295f3e
You will retrieve the API you added earlier.
{
 "sequences": [],
 "tiers": ["Unlimited"],
 "thumbnailUrl": null,
 "visibility": "PUBLIC",
 "visibleRoles": [],
 "visibleTenants": [],
 "cacheTimeout": 300,
 "endpointConfig": "{\"production_endpoints\": {\"url\": \"https://localhost:9443/am/sample/calculator/v1/api\",\"config\": null},\"sandbox_endpoints\": {\"url\": \"https://localhost:9443/am/sample/calculator/v1/api\",\"config\": null},\"endpoint_type\": \"http\" }",
 "subscriptionAvailability": null,
 "subscriptionAvailableTenants": [],
 "destinationStatsEnabled": "Disabled",
 "apiDefinition": "{\"basePath\":\"\\/calc\\/1.0\",\"paths\":{\"\\/divide\":{\"get\":{\"summary\":\"divide x by y\",\"x-auth-type\":\"Application & Application User\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"required\":true,\"type\":\"string\",\"in\":\"query\"},{\"name\":\"y\",\"required\":true,\"type\":\"string\",\"in\":\"query\"}],\"responses\":{\"200\":{}}}},\"\\/subtract\":{\"get\":{\"summary\":\"subtract y from x\",\"x-auth-type\":\"Application & Application User\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"required\":true,\"type\":\"string\",\"in\":\"query\"},{\"name\":\"y\",\"required\":true,\"type\":\"string\",\"in\":\"query\"}],\"responses\":{\"200\":{}}}},\"\\/add\":{\"get\":{\"summary\":\"add x and y\",\"x-auth-type\":\"Application & Application User\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"required\":true,\"type\":\"string\",\"in\":\"query\"},{\"name\":\"y\",\"required\":true,\"type\":\"string\",\"in\":\"query\"}],\"responses\":{\"200\":{}}}},\"\\/multiply\":{\"get\":{\"summary\":\"multiply x by y\",\"x-auth-type\":\"Application & Application User\",\"x-throttling-tier\":\"Unlimited\",\"produces\":[\"application\\/json\"],\"parameters\":[{\"name\":\"x\",\"required\":true,\"type\":\"string\",\"in\":\"query\"},{\"name\":\"y\",\"required\":true,\"type\":\"string\",\"in\":\"query\"}],\"responses\":{\"200\":{}}}}},\"host\":\"https:\\/\\/localhost:9443\",\"swagger\":\"2.0\",\"info\":{\"title\":\"Calculator\",\"description\":\"Simple calculator API to perform addition, subtraction, multiplication and division.\",\"version\":\"1.0\"}}",
 "responseCaching": "Disabled",
 "isDefaultVersion": false,
 "gatewayEnvironments": "Production and Sandbox",
 "businessInformation": {
  "technicalOwner": null,
  "technicalOwnerEmail": null,
  "businessOwner": null,
  "businessOwnerEmail": null
 },
 "transport": ["http", "https"],
 "tags": ["calculator"],
 "provider": "admin",
 "version": "1.0",
 "name": "CalculatorSampleAPI",
 "context": "/samplecalc",
 "id": "96758d8d-b121-4ae9-a752-76d138295f3e",
 "description": "Simple calculator API to perform addition, subtraction, multiplication and division.",
 "status": "CREATED"
}

Lets get all APIs and check our new API is there.

Generate token with apim:api_view scope:
curl -k -d "grant_type=password&username=admin&password=admin&scope=apim:api_view" -H "Authorization: Basic eGU5NGIxcXJlTFZscGxIalpHd0x0ZnJtdjM4YTpmT3VhMmNmc2RUb3dOMGFwekNjSjJ1SWZMTVlh" https://127.0.0.1:8243/token
Token generation response:
{"scope":"apim:api_view","token_type":"Bearer","expires_in":2357,"refresh_token":"528bd157f66df1db21c046737bb819eb","access_token":"ba5dc41a32387ff1db194bdf2b5d7c5f"}
Invoke get all APIs:
curl -H "Authorization: Bearer ba5dc41a32387ff1db194bdf2b5d7c5f" http://127.0.0.1:9763/api/am/publisher/v0.9/apis
Response:
< HTTP/1.1 200 OK
< Date: Sat, 26 Mar 2016 07:56:50 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Server: WSO2 Carbon Server
<

{
 "previous": "",
 "list": [{
  "provider": "admin",
  "version": "1.0",
  "name": "CalculatorSampleAPI",
  "context": "/samplecalc",
  "id": "96758d8d-b121-4ae9-a752-76d138295f3e",
  "description": "Simple calculator API to perform addition, subtraction, multiplication and division.",
  "status": "PUBLISHED"
 }],
 "count": 1,
 "next": ""
}


Publish the API


The API is now in CREATED state. We need to change its lifecycle state to PUBLISHED in order to make it visible in the Store. For this task we use the publisher API's /change-lifecycle API, which is secured with apim:api_publish scope.

Create a token with apim:api_publish scope:
curl -k -d "grant_type=password&username=admin&password=admin&scope=apim:api_publish" -H "Authorization: Basic eGU5NGIxcXJlTFZscGxIalpHd0x0ZnJtdjM4YTpmT3VhMmNmc2RUb3dOMGFwekNjSjJ1SWZMTVlh" https://127.0.0.1:8243/token
Response:
{"scope":"apim:api_publish","token_type":"Bearer","expires_in":3600,"refresh_token":"c99a3435230adceee296ec9517261b2a","access_token":"a44c384173298dc7db2b1a3a4fffc047"}
Publish the API:
curl -H "Authorization: Bearer a44c384173298dc7db2b1a3a4fffc047" -X POST "http://127.0.0.1:9763/api/am/publisher/v0.9/apis/change-lifecycle?apiId=96758d8d-b121-4ae9-a752-76d138295f3e&action=Publish" -v
Response:
< HTTP/1.1 200 OK
< Date: Sat, 26 Mar 2016 07:53:51 GMT
< Content-Length: 0
< Server: WSO2 Carbon Server

Accessing Store REST API

Like we did for accessing API Publisher, first of all we need to create an OAuth App using DCR endpoint to access Store REST API.

Creating an OAuth app to access Store REST API

curl -X POST -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -d @payload.json http://localhost:9763/client-registration/v0.9/register

Response:
{"appOwner":null,"clientName":null,"callBackURL":"www.google.lk","isSaasApplication":true,"jsonString":"{\"username\":\"admin\",\"redirect_uris\":\"www.google.lk\",\"client_name\":\"admin_rest_api_store\",\"grant_types\":\"urn:ietf:params:oauth:grant-type:saml2-bearer iwa:ntlm implicit refresh_token client_credentials authorization_code password\"}","clientId":"asjOw7p7XpmtFoLRHHP2i290WT0a","clientSecret":"baTZ4fYKXb04Ab3xhLVBecBGdI4a"}

Now we have created an OAuth App with clientId=asjOw7p7XpmtFoLRHHP2i290WT0a and cliendSecret=baTZ4fYKXb04Ab3xhLVBecBGdI4a. We can use it to generate access tokens in subsequent calls.
curl -k -d "grant_type=password&username=admin&password=admin&scope=apim:subscribe" -H "Authorization: Basic YXNqT3c3cDdYcG10Rm9MUkhIUDJpMjkwV1QwYTpiYVRaNGZZS1hiMDRBYjN4aExWQmVjQkdkSTRh" https://127.0.0.1:8243/token
Response:
{"scope":"apim:subscribe","token_type":"Bearer","expires_in":3600,"refresh_token":"4c67b8741c1eb3d07613af15776fd056","access_token":"1a2863559e2a017924a3a3bba9708b8f"}
Now we have received an OAuth access token 1a2863559e2a017924a3a3bba9708b8f for apim:subscribe scope. In API Managet 1.10.0 REST API, you can use the above token to all store related operations

View APIs in Store

We use /apis API in Store REST API.

curl -H "Authorization: Bearer 1a2863559e2a017924a3a3bba9708b8f" http://127.0.0.1:9763/api/am/store/v0.9/apis -v
< HTTP/1.1 200 OK
< Date: Sat, 26 Mar 2016 08:13:13 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Server: WSO2 Carbon Server
<

{
"previous": "",
"list": [{
"provider": "admin",
"version": "1.0",
"name": "CalculatorSampleAPI",
"context": "/samplecalc/1.0",
"id": "96758d8d-b121-4ae9-a752-76d138295f3e",
"description": "Simple calculator API to perform addition, subtraction, multiplication and division.",
"status": "PUBLISHED"
}],
"count": 1,
"next": ""
}

Creating an Application

To create applications we need to use /applications API as with application details in body as a POST request.

curl -H "Authorization: Bearer 1a2863559e2a017924a3a3bba9708b8f" -H "Content-Type: application/json" -X POST -d @payload.json "http://127.0.0.1:9763/api/am/store/v0.9/applications" -v
payload.json:
{
"callbackUrl": "www.google.com",
"throttlingTier": "Unlimited",
"description": "sample app description",
"name": "sampleapp"
}
Response:
< HTTP/1.1 201 Created
< Location: http://localhost:9763/api/am/store/v0.9/applications/3fa24818-5c42-43fa-9b87-9fa2be06e3fe
< Date: Sat, 26 Mar 2016 08:11:09 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Server: WSO2 Carbon Server
<

{
"groupId": null,
"callbackUrl": "www.google.com",
"subscriber": "admin",
"throttlingTier": "Unlimited",
"applicationId": "3fa24818-5c42-43fa-9b87-9fa2be06e3fe",
"name": "sampleapp",
"keys": [],
"description": "sample app description",
"status": "APPROVED"
}

If you encounter the following error for first time accessing Store applications API after the user is added as a subsciber. Please try login to the Store web application once (or you can use old jaggery Store login API only once) and then invoke the applications API. This is a known limitation in API Manager 1.10.0.
< HTTP/1.1 500 Internal Server Error
< Date: Sun, 20 Mar 2016 13:47:21 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: close
< Server: WSO2 Carbon Server
<
* Closing connection 0
{"moreInfo":"","code":500,"description":"The server encountered an internal error. Please contact administrator.","message":"Internal server error","error":[]}

Generate application keys

To generate keys to the new application we need to use /generate-keys API. We need to provide application-id as a parameter and some other details as the payload.
curl -H "Authorization: Bearer 1a2863559e2a017924a3a3bba9708b8f" -H "Content-Type: application/json" -X POST -d @payload.json  "http://127.0.0.1:9763/api/am/store/v0.9/applications/generate-keys?applicationId=3fa24818-5c42-43fa-9b87-9fa2be06e3fe" -v
payload.json:
{
  "validityTime": "3600",
  "keyType": "PRODUCTION",
  "accessAllowDomains": ["ALL"
  ]
}
Response:
< HTTP/1.1 200 OK
< Date: Sat, 26 Mar 2016 08:17:03 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Server: WSO2 Carbon Server
<

"consumerKey": "GeJPyO1_sFHQ7sfyhwYd87TN_Kka",
"consumerSecret": "7QCdD4FgPCRvRnWnFuWPTmYos0Aa",
"keyState": "APPROVED",
"keyType": "PRODUCTION",
"supportedGrantTypes": ["urn:ietf:params:oauth:grant-type:saml2-bearer", "iwa:ntlm", "refresh_token", "client_credentials", "password"],
"token": {
"validityTime": 3600,
"accessToken": "0dc6c1e6b58be2410c779e1366aced4c",
"tokenScopes": ["am_application_scope", "default"]
}
}

Subscribe to the API

To add a subscription with the sample calculater API we added and the sample application we need to use /subscriptions API.
curl -H "Authorization: Bearer 1a2863559e2a017924a3a3bba9708b8f" -H "Content-Type: application/json" -X POST  -d @payload.json "http://127.0.0.1:9763/api/am/store/v0.9/subscriptions" -v
payload.json:
{
    "tier": "Unlimited",
    "apiIdentifier": "96758d8d-b121-4ae9-a752-76d138295f3e",
    "applicationId": "3fa24818-5c42-43fa-9b87-9fa2be06e3fe"
}
Response:
< HTTP/1.1 201 Created
< Location: http://localhost:9763/api/am/store/v0.9/subscriptions/558a42a6-8c8e-4bfa-9305-7a9912d0cabe
< Date: Sat, 26 Mar 2016 08:14:37 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Server: WSO2 Carbon Server
<

{
"tier": "Unlimited",
"subscriptionId": "558a42a6-8c8e-4bfa-9305-7a9912d0cabe",
"apiIdentifier": "admin-CalculatorSampleAPI-1.0",
"applicationId": "3fa24818-5c42-43fa-9b87-9fa2be06e3fe",
"status": "UNBLOCKED"
}

Invoke the API

Now we are done with Publisher and Store REST APIs for creating APIs, applications, generating keys and adding subscriptions. Lets spend a small amount of time trying invoking our newly created API to make sure everything is fine :).

We got the clientId and clientSecret as the response when creating our application "sampleapp". We can use that to generate an access token to invoke the API. We add base64Encoded as Authorization : Basic header like we did before.
curl -k -d "grant_type=password&username=admin&password=admin" -H "Authorization: Basic R2VKUHlPMV9zRkhRN3NmeWh3WWQ4N1ROX0trYTo3UUNkRDRGZ1BDUnZSblduRnVXUFRtWW9zMEFh" http://127.0.0.1:8280/token -v
< HTTP/1.1 200 OK
< Content-Type: application/json
< Pragma: no-cache
< Cache-Control: no-store
< Date: Sat, 26 Mar 2016 08:21:14 GMT
< Transfer-Encoding: chunked
<

{"scope":"default","token_type":"Bearer","expires_in":79,"refresh_token":"1ef74fa5bb4d71d0d5fa5956a44dfb98","access_token":"c4eecb842f00de8ed5aedf66e1b72bb5"}

Now we invoke our sample API using that access token.
curl -X GET --header "Accept: application/json" --header "Authorization: Bearer c4eecb842f00de8ed5aedf66e1b72bb5" "https://127.0.0.1:8243/samplecalc/1.0/add?x=1&y=2" -k -v
< HTTP/1.1 200 OK
< Access-Control-Allow-Headers: authorization,Access-Control-Allow-Origin,Content-Type
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET
< Content-Type: application/json
< Date: Sat, 26 Mar 2016 09:16:10 GMT
< Transfer-Encoding: chunked
<
{"answer": "3.0"}


Wednesday, February 10, 2016

API Manager New REST API - The First Step

There are three Jax-RS web applications related to API Manager new REST API.

1. Publisher Jax-RS web application
The JaxRS REST API web application which is responsible for all Publisher web app related functions.

2. Store Jax-RS web application
The JaxRS REST API web application which is responsible for all Store web app related functions.

3. Client-Registration Jax-RS web application
The JaxRS REST API web application which is responsible for creating OAuth applications in order to access Store or Publisher REST APIs.

Invoke DCR and create an OAuth Application

For this step you can also refer API Manager REST API documentation [1], but I will state the basic steps in brief.

As the first step you have to invoke the client-registration API. This is a new JaxRS web app, introduced in API Manager 1.10.0 version to create OAuth applications to invoke the new REST API. It has initial version of v0.9.

The API is secured with Basic authentication so you need to provide base64encoded(username:password) as the Authorization: Basic header.
curl -X POST -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" 
-d @payload.json http://localhost:9763/client-registration/v0.9/register

Sample payload.json file:
{
    "callbackUrl": "www.google.lk",
    "clientName": "rest_api_publisher",
    "tokenScope": "Production",
    "owner": "admin",
    "grantType": "password refresh_token",
    "saasApp": true
}
In this payload you specify "clientName" which is the OAuth application name.

After sending the above request you will get a response like this:

HTTP/1.1 201 Created
Date: Sun, 20 Mar 2016 03:29:57 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Server: WSO2 Carbon Server

{
   "jsonString":"{\"username\":\"admin\",\"redirect_uris\":\"www.google.lk\",\"client_name\": \"admin_rest_api_publisher\",\"grant_types\":\"urn:ietf:params:oauth:grant-type:saml2-bearer iwa:ntlm implicit refresh_token client_credentials authorization_code password\"}",
   "appOwner":null,
   "clientName":null,
   "callBackURL":"www.google.lk",
   "isSaasApplication":true,
   "clientId":"xe94b1qreLVlplHjZGwLtfrmv38a",
   "clientSecret":"fOua2cfsdTowN0apzCcJ2uIfLMYa"
}

Now you have successfully created an OAuth application. Now you can invoke the Token API [2] to create an access token using the received client ID and client Secret. This is exactly same as when you invoke token API to create an access token to invoke an API published in API Manager.

This supports all OAuth2 grant types that API Manager supports and here I am using password grant type to create an access token.

curl -k -d "grant_type=password&username=admin&password=admin&scope=<scopes>" 
-H "Authorization: Basic <base64encoded(clientid:clientsecret)> https://127.0.0.1:8243/token

Scopes

One thing to note here is the scope field. In new REST API there is a specific scope mapped to resource verb combinations. For example if you need to invoke Get All APIs in Publisher REST API, your token need to have apim:api_view scope.

The REST API consists of following OAuth scopes. As an API creator, publisher or subscriber you need to have access to following set of scopes:

As an API Creator:
  • apim:api_view  - to view APIs
  • apim:api_create - to create new APIs
  • apim:subscription_view - to view subscriptions of APIs
  • apim:subscription_block - to block/unblock subscription of APIs
  • apim:tier_view - to view tiers
As an API Publisher:
  • apim:api_view  - to view APIs
  • apim:api_publish - to change lifecycle states of APIs (publish, deprecate, retire APIs etc)
As an API Subscriber:
  • apim:api_subscribe - create applications, view applications, subscribe to APIs and all Store related operations
As an Administrator:
  • ++ all creator scopes
  • ++ all publisher scopes
  • ++ all subscriber scopes
  • apim:tier_manage - to block unblock subscribing to tiers in Store based on user's roles

Tip
--------
You can just try asking for an invalid random scope and check what you receive.

curl -k -d "grant_type=password&username=admin&password=admin&scope=random_invalid_scope" 
-H "Authorization: Basic eGU5NGIxcXJlTFZscGxIalpHd0x0ZnJtdjM4YTpmT3VhMmNmc2RUb3dOMGFwekNjSjJ1SWZMTVlh" 
https://127.0.0.1:8243/token -v

Response:

< HTTP/1.1 200 OK
< Content-Type: application/json
< Pragma: no-cache
< Cache-Control: no-store
< Date: Sun, 20 Mar 2016 07:14:59 GMT
< Transfer-Encoding: chunked
<

* Connection #0 to host 127.0.0.1 left intact
{"scope":"default","token_type":"Bearer","expires_in":3600,"refresh_token":"1e2f7d03297f51b2bf4b0762efa9546a",
"access_token":"081f892624caeb3be2b1a1ab22b00316"}

You can see you receives an scope called default but not what you requested.
--------

You can request single or many scopes at once. When requesting multiple scopes you need to give them space separated.

Let's request all scopes related to an API creator. See the sample curl command below.

curl -k -d "grant_type=password&username=admin&password=admin&scope=apim:api_view apim:api_create 
apim:subscription_view apim:subscription_block apim:tier_view" 
-H "Authorization: Basic eGU5NGIxcXJlTFZscGxIalpHd0x0ZnJtdjM4YTpmT3VhMmNmc2RUb3dOMGFwekNjSjJ1SWZMTVlh" 
https://127.0.0.1:8243/token -v

You will receive following response:

< HTTP/1.1 200 OK
< Content-Type: application/json
< Pragma: no-cache
< Cache-Control: no-store
< Date: Sun, 20 Mar 2016 07:09:41 GMT
< Transfer-Encoding: chunked
<
* Connection #0 to host 127.0.0.1 left intact
{"scope":"apim:api_create apim:api_view apim:subscription_block apim:subscription_view apim:tier_view",
"token_type":"Bearer","expires_in":3600,"refresh_token":"dc760c94e3c8a5c4c3d263b14708b275","access_token":"fb3db536b07f2a1da0185d82b0887848"}
You can see you received all scopes you requested -  "scope":"apim:api_create apim:api_view apim:subscription_block apim:subscription_view apim:tier_view" .  
Before going further you have to make sure you have received the scopes you requested.

Invoking a sample API

Now we are done with getting an access token. Lets try to invoke an API in Publisher.

An easiest API for a beginner is Get All Tiers API as it does not require any prerequisites. See that API in documentation [3]

Request path                  : https://localhost:9443/api/am/publisher/v0.9/apis/tiers/api
Request HTTP method  : GET
Scope                             : apim:tier_view

Use the following curl command. Replace the access token with what you received from token API. Lets use the access token we got from invoking the token API. We have to use it as Authorization: Bearer header. Just same as when we invoke an API published in API Manager.

curl -k -H "Authorization: Bearer fb3db536b07f2a1da0185d82b0887848"
https://127.0.0.1:9443/api/am/publisher/v0.9/tiers/api -v
You will be able to see following response.

< HTTP/1.1 200 OK
< Date: Sun, 20 Mar 2016 08:19:56 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Server: WSO2 Carbon Server
<
* Connection #0 to host 127.0.0.1 left intact
{  
   "previous":"",
   "list":[  
      {  
         "unitTime":60000,
         "tierPlan":"FREE",
         "tierLevel":"api",
         "stopOnQuotaReach":true,
         "requestCount":1,
         "description":"Allows 1 request(s) per minute.",
         "name":"Bronze",
         "attributes":{  

         }
      },
      {  
         "unitTime":60000,
         "tierPlan":"FREE",
         "tierLevel":"api",
         "stopOnQuotaReach":true,
         "requestCount":20,
         "description":"Allows 20 request(s) per minute.",
         "name":"Gold",
         "attributes":{  

         }
      },
      {  
         "unitTime":60000,
         "tierPlan":"FREE",
         "tierLevel":"api",
         "stopOnQuotaReach":true,
         "requestCount":5,
         "description":"Allows 5 request(s) per minute.",
         "name":"Silver",
         "attributes":{  

         }
      },
      {  
         "unitTime":0,
         "tierPlan":null,
         "tierLevel":"api",
         "stopOnQuotaReach":true,
         "requestCount":0,
         "description":"Allows unlimited requests",
         "name":"Unlimited",
         "attributes":{  

         }
      }
   ],
   "count":4,
   "next":""
}

References:

[1] https://docs.wso2.com/display/AM1100/apidocs/publisher/index.html#guide
[2] https://docs.wso2.com/display/AM1100/Token+API
[3] https://docs.wso2.com/display/AM1100/apidocs/publisher/index.html#!/operations#TiersApi#tiersTierLevelGet