Part 3: Adding API Gateway and the Article Page
Tags: aws, cloud, serverless, database
Published: 2021-01-17 18:53:35

<p>In this post we will add API Gateway to our CloudFormation template and add the article page endpoint to API Gateway using OpenAPI. &nbsp;We will demo that new endpoint being used to display the sample article we added directly to the DynamoDB table in the previous post.</p><p>This post picks up where we left off in <a target='_blank' href='https://www.jonholman.com/ComputelessBlog/part-2-planning-the-data-model'>Part 2: Planning the Data Model</a>. &nbsp;If you did not go through that post, you can get the project files we will be using as our starting point <a target='_blank' href='https://github.com/JonHolman/ComputelessBlog/tree/part-2-planning-the-data-model'>here</a>.</p><p>First we need to create an IAM role for our API Gateway to use. &nbsp;This role will give API Gateway the permissions it needs to read the data from our DynamoDB Table. &nbsp;We will then create our API Gateway and add an output to our CloudFormation template. &nbsp;That output we are adding will return the URL to our new endpoint. &nbsp;To add these CloudFormation resources, add the following to your template.yaml file.</p>
{% gist https://gist.github.com/JonHolman/23290dce6352cef3b657d3bcfa0343e7.js %}<p>In the API Gateway definition above, you will notice that it is very brief and it references another file openapi.yaml. &nbsp;That is the OpenAPI definition file and almost all of the API definition occurs in that file. &nbsp;Create a new file in your project named openapi.yaml with the content below:</p>{% gist https://gist.github.com/JonHolman/31d579893ee8956583ef4a9c8666c37c.js %}<p>Let's walk through what is going on in this openapi.yaml file. &nbsp;The important part of this file is the paths section. &nbsp;Right now we are defining only one path, but it is a very powerful path definition, using what is called a greedy path parameter. &nbsp;The path specification of <code>/{path+}</code> defines that any request that is more than just the root of the API Gateway endpoint will be accepted by this route. &nbsp;Also everything in the URL after the API Gateway's root will be available to us as a parameter named path. &nbsp;On the next line we specify the only HTTP verb that we are configuring for that path at this time, the GET HTTP verb.</p><p>Now for the section <code>x-amazon-apigateway-integration</code> this is where all of the magic happens with API Gateway and it proxying DynamoDB for us. &nbsp;The highlights are:</p><ol><li>credentials - this references the IAM role that we created in template.yaml which gives our API Gateway permissions to access our DynamoDB table.</li><li>uri - this is where we specify what action we want this endpoint to execute on our DynamoDB table, we want to Query a DynamoDB table in us-east-1 so our uri is 'arn:aws:apigateway:us-east-1:dynamodb:action/Query'</li><li>responseTemplates - this is where we define exactly how we want the response to be presented to the requestor. &nbsp;We have Velocity Template Language (VTL) available to use to transform the response however we need.</li><li>requestTemplates - this is where we define exactly how we want our request to be executed against DynamoDB. &nbsp;We also have VTL available to us here, so that we can transform the request from how it comes into API Gateway to exactly how it needs to be for DynamoDB. &nbsp;In this example I am using the intrinsic function Fn::Join to substitute in our DynamoDB table name (named the same as our stack) so that our table name is not hardcoded.</li><li>httpMethod - For DynamoDB actions the httpMethod from API Gateway to DynamoDB should always be POST.</li></ol><p>One last edit we should make to our template.yaml file, is we will add a Globals: section and in there define OpenApiVersion: '3.0.1'. &nbsp;This setting is necessary to resolve a <a target='_blank' href='https://github.com/aws/serverless-application-model/issues/191'>bug with AWS SAM</a> and without this setting we end up with two Stages being created in API Gateway - the stage Prod that we are specifying and an additional stage named Stage. &nbsp;I usually create the Globals section in template.yaml after Description (at line 3), the additional block will look like:</p>{% gist https://gist.github.com/JonHolman/b4cfa84eb53c61fee8d3e0abcc51b2f8.js %}<p>Now we can run sam deploy (if this is your first time, run sam deploy --guided and I suggest allowing it to save your configuration to a file) to update our CloudFormation stack. &nbsp;When AWS SAM completes updating our CloudFormation stack it will return the URL to our API Gateway as WebSiteOrigin. &nbsp;For me the URL was <a target='_blank' href='https://40hfrzhqoj.execute-api.us-east-1.amazonaws.com/Prod.'>https://40hfrzhqoj.execute-api.us-east-1.amazonaws.com/Prod.</a> &nbsp;We can browse to that URL with our sample record's sk value (/sample/post-1) appended to the end, and you will see a display like below:</p><figure class='image'><img src='https://www.jonholman.com/part-3-adding-api-gateway-and-article-page-1.png'></figure><p>This is displaying the values we set in that DynamoDB sample record to our browser, via API Gateway. &nbsp;Now we probably want this information to be displayed in a nicer way than this, so we need to add some HTML and accompanying CSS. &nbsp;For that I will turn to w3schools.com which has many prebuilt HTML templates to choose from. I will use <a target='_blank' href='https://www.w3schools.com/w3css/tryit.asp?filename=tryw3css_templates_blog&amp;stacked=h'>their blog template</a>.</p><p>I made some minor changes to that template, removing items that we will not cover adding functionality for at this point (most popular posts, tagging posts, comments) and removing placeholder images. We can add that functionality later in this series if it is desired.</p><p>The page template is somewhat large and is quite distracting when defined within the CloudFormation or OpenAPI template files, so I opted to move it to another file and import it from there into a CloudFormation mapping (another file cannot be imported into the openapi.yaml file). &nbsp;In the future we will also need to associate this same page template with our home page, to avoid a lot of duplication, so having it defined elsewhere and able to be reference it where needed will make that cleaner as well.</p><p>To do that, let's first add the mapping section to our template.yaml file, I like to place the mappings between global and resources.</p>{% gist https://gist.github.com/JonHolman/da992c89dae226403999ca8176989e31.js %}<p>Then create the page.yaml file. &nbsp;This is the template from w3schools, minus the sections I removed, with our VTL variables being placed within to put our articles stored in DynamoDB in to the template.</p>{% gist https://gist.github.com/JonHolman/ebc69002eef38395a309a631b7d78b13.js %}<p>and finally let's replace the responseTemplates section in the openapi.yaml file with this below to use that new CloudFormation mapping for its response template.</p>{% gist https://gist.github.com/JonHolman/f2cfc0927bf801256e40db0cd8165b2e.js %}<p>Now, let's run sam deploy again and then browse to the page</p><figure class='image'><img src='https://www.jonholman.com/part-3-adding-api-gateway-and-article-page-2.png'></figure><p>That's what I was looking for. &nbsp;I am not a front-end developer. &nbsp;If you are, I'm sure you can make a page template that fits your style much better, but for me, this works.</p><p>Please note that, I have noticed for the API Gateway definition to update and deploy the changes, the openapi.yaml file needs to be modified. &nbsp;Just modifying the page.yaml file that is referenced within it via a mapping is not enough, so I usually just make minor edits to the description field at the top of the OpenAPI file, like add a 1.</p><p>Our project directory at the end of this post is available <a target='_blank' href='https://github.com/JonHolman/ComputelessBlog/tree/part-3-adding-api-gateway-and-article-page'><u>here</u></a>.</p><p>Thanks for reading. &nbsp;If you have any feedback or questions, please leave a comment or message me on Twitter/LinkedIn (links on the right side bar).</p><p><a target='_blank' href='https://www.jonholman.com/ComputelessBlog/part-4-adding-category-landing-and-home-page'>Continue with the next article in this series.</a></p>