Monday, August 31, 2015

How Swagger helped me with AWS API Gateway


Motive and background

Recently, I had to stumble onto a problem where I had to apply some authentication on top of considerable large legacy code. Time was pretty much limited, I had look for ways of quick solution. Then, I was introduced to API gateway from Amazon, from the outset which looked a perfect fit for my problem, why? firstly my API was running on EC2 and secondly, I did not want a convoluted authentication mechanism, so that I can set to each of my API end point to demand an access token, before it is invoked. But again, API interface was quite a large one, I simply had write an invocation points for each method. And then the Swagger came along.
What is AWS API Gateway, it is a managed service platform, that enables you to write, publish your new APIs or integrate with other third party API and still scale it; not least, some monitoring services such logs and etc. It can act as a façade face of your existing API and add some additional functionality with few Lambda Functions. The getting started guide helped me to good extent.
How swagger came into picture?,  you have a system and there are some REST APIs, certainly you may not have the control of which language they were written; and at some point, you want to talk with them, and if your system can talk to any of these API in a language agnostic way and still if you can also understand what is going on, wouldn’t it be great? that’s what exactly the swagger does. Swagger works on swagger definition, using a swagger you can write an implementation (using swagger code generation tool), or generate definition file out of existing API that in turn will be used by client. So using the swagger, I generated the definition then used that definition file to import the API resource points to AWS API gateway( this simply the methods of my existing API), don’t get confused over “resource”, it is just AWS way marking the methods of API.
setup

Overview of Implementation

Essentially my steps are based on this well written guide, typically this is 3 step process
  1. Adding Swagger's dependencies to your project.
  2. Hook Swagger into your JAX-RS application configuration.
  3. Configure and Initialize Swagger.
My API was written using REST easy, this how started add maven dependency
<dependency>
  <groupId>io.swagger</groupId>
  <artifactId>swagger-jaxrs</artifactId>
  <version>1.5.0</version>
</dependency>

then you can let the swagger to scan your root context, or add some provider class to your rest easy providers, I chose the add some providers
<servlet>
<servlet-name>Jersey2Config</servlet-name>
<servlet-class>io.swagger.jaxrs.config.DefaultJaxrsConfig</servlet-class>
<init-param>
<param-name>api.version</param-name>
<param-value>1.0.0</param-value>
</init-param>
<init-param>
<param-name>swagger.api.basepath</param-name>
<param-value>http://localhost:8080/api</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
Just a servlet with no path mapping, which will be started during the application startup.

Are done, yes but only with the setup, still you need to decorate your API with annotations. So that swagger can catch them, lets do it!, it would be likely done as follows,

@Path("/ping")
@Api(value = "/ping", description = "All is well")
public class PingService {

private static final Logger LOGGER = LoggerFactory
.getLogger(PingService.class);

@GET
@ApiOperation(value = "Just ping", notes = "just ping.", position = 1)
@Path("/hello")
@Produces(MediaType.APPLICATION_JSON)
@ApiResponses(value = {
@ApiResponse(code = 400, message = "system down"),
@ApiResponse(code = 404, message = "No available") })
public Response ping() {
LOGGER.info("Ping service active");
return new Response(ResponseStatus.SUCCESS,
"Welcome to TeletecAO2RWService");
}

}

And you have to annotate all the model objects as well,

So what do we have here now, we get the swagger definition file from context root of your API, such as above http://localhost:8080/api/swagger.json, which will look something like this very basic


{
"apiVersion": "",
"apis": [
],
"basePath": "http://192.168.1.1:8000",
"models": {
},
"resourcePath": "/api",
"swaggerVersion": "1.2"
}




while a full fledged definition may be like this

well swagger does the work for you, it crawls from your root context and find all API paths from there. At this point you don’t have to worry about any daunting size of definition file it generates.

So how to get this imported into the our API gateway, we have swagger importer, all you do is get the aws-apigateway-swagger-importer-{version}-dependencies.jar to your local folder and run the following,

./aws-api-import.sh --create path/to/swagger.json --profile optimusprime

Remember, the "optimusprime" is the profile that contains the valid access key and secret keys for you aws api gateway. but one thing to note that, you may to run it on your Linux machine with AWS CLI installed. And if you are to build this from maven scratch, build it from Linux machine itself. I had waste an hour debugging my build and moving the my EC2 RHEL instance. Script aws-api-import.sh will struggle to execute in your Linux environment if you do so.

Having everything worked fine, importer ran properly you now will see the resource points listed in your AWS. If you feeling relaxed at this point, all you need to do is just finish off with your rest of AWS API work.

Click on these method, and map it to your API, in my case it was on EC2, so when selecting the integration type, due to the fact my API was on EC2, I chose AWS service proxy. Before this, I created ARN for my existing service using a role. How exactly do that? you can find here.



Add authentication


To to your resource, and select method GET/POST or what ever, and select “Method Request”

API-Get

API-Get_security

You can select AWS-IAM and select the security token, at least this is all I had to, in your case if you insist the client to pass some header values you can add and then wire some lambda function to validate them (lambda function are interesting too, I suggest you to take a look at them). And then just navigate through rest of the flow to do the mapping etc. Once all done just deploy your API via deploy tool.

So what is the url, that you will be invoking the ARN which you can find the the “Method Request”, it will be such as this

arn:aws:execute-api:us-west-2:900272013338:02mubm2sui/*/GET/department

There is a pretty good written documentation from AWS for this, (if I can understand, your grandma will definitely understand), try this.

So that’s how the Rover landed in Mars, kinda cool IMHO, AWS api gateway seems to amazing feature rich tool, for a while I was wondering if this is an orchestration tool, such as Mule, but I would hardly think if that was the intention of API Gateway, probably not.

Getting the the definition file for other language written such Jersey or etc should be straight forward.

 Common Errors


1. ERROR - Could not load AWS configuration. Please run 'aws configure' - This is due to that importer could not find config file. which should be located at {user.home}/.aws/config. So you may have to create a one. To do this you need to install AWS CLI if you have not already done, instruction provided here. Once done you need to do configure a profile via
aws configure --profile optimusprime

you will be prompted for you access and secret keys.

2. ERROR -  Cross-account pass role is not allowed. (Service: null; Status Code: 403; Error Code: null; Request ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)

This is because you have forgot to put you account id, "x-amazon-apigateway-integration" section of swagger definition file

so once you have done it should be something like as follows, ( just replace ACCOUNT_ID with your proper account id

.....
"x-amazon-apigateway-integration" : {
                    "type" : "aws",
                    "uri" : "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:865555555:function:myFunction/invocations",
                    "httpMethod" : "POST",
                    "credentials" : "arn:aws:iam::865555555:role/lambda_exec_role",
                    "requestTemplates" : {
                        "application/json" : "json request template 2",
                        "application/xml" : "xml request template 2"
                    }
.....

3. ERROR-  Invalid ARN specified in the request
This is again usually arises from wrong account id of format, remember your credential should be some thing like  "arn:aws:iam::865555555:role/lambda_exec_role", with exact number of colons.

4. Everything gone fine, but still i can't see the API listed in my console.
Nothing to worry, he might have been listed under another AWS region. Check the uri, if your under us-west-2, above uri should be

.....
"uri" : "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:865555555:function:myFunction/invocations"
.....

 

 

10 comments:

  1. where should i put my ACCOUNT_ID ?

    ReplyDelete
  2. Hi,

    I releases a JAX-RS implementation for AWS Lambda, maybe it helps: https://github.com/lambadaframework/lambadaframework

    ReplyDelete
  3. I always enjoy reading quality articles by an individual who is obviously knowledgeable on their chosen subject. Ill be watching this post with much interest. Keep up the great work, I will be back
    Selenium training in Chennai

    Selenium training in Bangalore
    Java training in Chennai

    Java training in Bangalore

    ReplyDelete
  4. Thank you for sharing your thoughts and knowledge on this topic. This is really helpful and informative, as this gave me more insight to create more ideas and solutions for my plan. I would love to see more updates from you.
    Salesforce Training in Chennai

    Salesforce Online Training in Chennai

    Salesforce Training in Bangalore

    Salesforce Training in Hyderabad

    Salesforce training in ameerpet

    Salesforce Training in Pune

    Salesforce Online Training

    Salesforce Training

    ReplyDelete
  5. This is my first time visit to your blog and I am very interested in the articles that you serve. Provide enough knowledge for me. Thank you for sharing useful and don't forget, keep sharing useful info:

    Data Science Training in Gurgaon
    Bigdata Hadoop Training in Gurgaon
    Spark Training in Gurgaon

    ReplyDelete
  6. The Original Forex Trading System: exness login Is The Original Forex Trading System. It Is 100% Automated And Provides An Easy-to-follow Trading System. You Get Access To Real-time Signals, Proven Methods, And A Money-back Guarantee.

    ReplyDelete
  7. Very Nice Blog…Thanks for sharing this information with us. Here am sharing some information about training institute.
    digital transformation services by NGS

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete