<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ cloudformation - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ cloudformation - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 18 May 2026 04:49:50 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/cloudformation/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build and Deploy a GraphQL Server in AWS Lambda Using Node.js and CloudFormation ]]>
                </title>
                <description>
                    <![CDATA[ By subash adhikari Introduction I have been building GraphQL APIs in a Serverless environment for over 3 years now. I can't even imagine working with RESTful APIs anymore. Combine the power of GraphQL with the scalability of AWS Lambda, and you have ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-and-deploy-graphql-server-in-aws-lambda-using-nodejs-and-cloudformation/</link>
                <guid isPermaLink="false">66d4614ad14641365a05096d</guid>
                
                    <category>
                        <![CDATA[ aws lambda ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cloudformation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GraphQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 19 May 2020 20:42:16 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/05/banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By subash adhikari</p>
<h1 id="heading-introduction">Introduction</h1>
<p>I have been building GraphQL APIs in a Serverless environment for over 3 years now. I can't even imagine working with RESTful APIs anymore. Combine the power of GraphQL with the scalability of AWS Lambda, and you have a server that can handle infinite amounts of traffic.</p>
<p>In this tutorial, we will build and deploy a GraphQL server to AWS Lambda and access it via an API Gateway endpoint. We will use CloudFormation and the AWS CLI to deploy all our AWS Resources and application code.</p>
<h2 id="heading-what-well-cover">What we'll cover</h2>
<ol>
<li>Build a GraphQL Server using Apollo</li>
<li>Deploy that GraphQL Server to Lambda</li>
<li>Use API Gateway to proxy requests to Lambda</li>
<li>Use CloudFormation to deploy application stack to AWS</li>
<li>Set up Lambda for local development.</li>
</ol>
<p>TL;DR – You can get the full source code for the application from <a target="_blank" href="https://github.com/adikari/apollo-server-lambda-nodejs/tree/server-setup">Github</a>.</p>
<h1 id="heading-what-is-graphql">What is GraphQL?</h1>
<p><a target="_blank" href="https://graphql.org/">GraphQL</a> is a query language for describing APIs using a strongly typed schema system. A GraphQL server fulfills those queries using existing data. Following are a few of the main advantages of using GraphQL.</p>
<h2 id="heading-query-only-what-your-application-needs">Query only what your application needs</h2>
<p>Unlike REST APIs, GraphQL enables clients to query precisely and only what they need. The server fulfills the client’s request by returning only what the client is asking for.</p>
<h2 id="heading-graphql-uses-a-strongly-typed-system">GraphQL uses a strongly typed system</h2>
<p>The strongly typed system of GraphQL enables users to introspect the entire schema. And the GraphQL API serves as clear documentation about the capabilities of the server and notifies you about errors during development.</p>
<h2 id="heading-you-can-compose-your-queries-in-a-single-request">You can compose your queries in a single request</h2>
<p>With GraphQL, you can query multiple resources and get combined responses with a single request. With fewer requests, apps using GraphQL perform much faster.</p>
<h1 id="heading-what-is-aws-lambda">What is AWS Lambda?</h1>
<p>AWS Lambda is a compute service offered by AWS that lets you run your application code without having to manage any servers. AWS manages all the overhead like infrastructure, security, resources, operating system, and patches so developers can focus on just building the application.</p>
<p>Let’s get started…</p>
<h1 id="heading-setting-up-the-project">Setting up the project</h1>
<p>Let’s start by creating a project folder. Then, change into the directory and initialise a Node project. I am using <code>node 10.x</code> in the examples. You can install the Node version of your choice using <a target="_blank" href="https://github.com/asdf-vm/asdf">asdf</a>.</p>
<pre><code class="lang-bash">mkdir apollo-server-lambda-nodejs 
<span class="hljs-built_in">cd</span> apollo-server-lambda-nodejs 
yarn init
</code></pre>
<p>Next, create a folder that houses all our source code.</p>
<pre><code class="lang-bash">mkdir src
</code></pre>
<p>Finally, create an index file inside the <code>src</code> directory that serves as the lambda handler.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> src
touch index.js
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/initialize.png" alt="Image" width="600" height="400" loading="lazy">
<em>Initialize node project</em></p>
<p>Populate the index file with the following code.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> () =&gt; {  
    <span class="hljs-keyword">return</span> { 
        <span class="hljs-attr">body</span>: <span class="hljs-string">'Hello from Lambda'</span> 
    };
};
</code></pre>
<p>The above code is a very simple Lambda handler which will return <code>Hello from Lambda</code> when invoked. Let's first deploy our code to AWS Lambda.</p>
<h1 id="heading-package-the-application-code">Package the application code</h1>
<p>Before we can deploy our code to Lambda, we need to create a zip of our application and upload it to an S3 bucket. We are using AWS CLI to create the bucket. Set up AWS CLI now by following <a target="_blank" href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html">this guide</a> if you have not already done so.</p>
<p>Create an S3 bucket to use for deploying our code to Lambda. Pick a unique name for your S3 bucket. The bucket names are unique globally across all AWS Regions.</p>
<pre><code class="lang-bash">aws s3 mb s3://lambda-deploy-asln
</code></pre>
<p>Create an archive of the application using the zip command and verify the files inside the zip.</p>
<pre><code class="lang-bash">zip -rq dist-latest.zip src package.json 
zipinfo dist-latest.zip
</code></pre>
<p>Copy the zip file to S3 using the AWS CLI command.</p>
<pre><code class="lang-bash">aws s3 cp dist-latest.zip s3://lambda-deploy-asln/dist-latest.zip
</code></pre>
<p>Finally, use the following command to verify that the file exists in S3.</p>
<pre><code class="lang-bash">aws s3 ls s3://lambda-deploy-asln
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/2-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Copy application package to S3</em></p>
<p>Now that we have deployed the packaged application to S3, next we need to set up our Lambda and API Gateway in AWS. In the next section, we'll use CloudFormation to set up all necessary AWS Resources.</p>
<h1 id="heading-set-up-aws-lambda-with-api-gateway-proxy-integration">Set up AWS lambda with API gateway proxy integration</h1>
<p>CloudFormation is an AWS service that helps us to write infrastructure as code. CloudFormation makes it very simple to create and manage our application resources. Let’s use CloudFormation to define our stack.</p>
<p>Create a file named <code>cloudformation.yml</code> at the root of the project.</p>
<pre><code class="lang-bash">touch cloudformation.yml
</code></pre>
<p>Add the following code to the <code>cloudformation.yml</code></p>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-attr">Description:</span> <span class="hljs-string">GraphQL</span> <span class="hljs-string">server</span> <span class="hljs-string">on</span> <span class="hljs-string">AWS</span> <span class="hljs-string">lambda</span>

<span class="hljs-attr">Parameters:</span>
  <span class="hljs-attr">Version:</span>
    <span class="hljs-attr">Description:</span> <span class="hljs-string">Application</span> <span class="hljs-string">version</span> <span class="hljs-string">number</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">String</span>

  <span class="hljs-attr">BucketName:</span>
    <span class="hljs-attr">Description:</span> <span class="hljs-string">S3</span> <span class="hljs-string">bucket</span> <span class="hljs-string">name</span> <span class="hljs-string">where</span> <span class="hljs-string">the</span> <span class="hljs-string">source</span> <span class="hljs-string">code</span> <span class="hljs-string">lives</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">String</span>

<span class="hljs-attr">Resources:</span>
  <span class="hljs-attr">LambdaFunction:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">AWS::Lambda::Function</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">Code:</span>
        <span class="hljs-attr">S3Bucket:</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">BucketName</span>
        <span class="hljs-attr">S3Key:</span> <span class="hljs-type">!Sub</span> <span class="hljs-string">dist-${Version}.zip</span>
      <span class="hljs-attr">Handler:</span> <span class="hljs-string">src/index.handler</span>
      <span class="hljs-attr">Description:</span> <span class="hljs-string">GraphQL</span> <span class="hljs-string">Apollo</span> <span class="hljs-string">Server</span>
      <span class="hljs-attr">Role:</span> <span class="hljs-type">!GetAtt</span> <span class="hljs-string">LambdaExecutionRole.Arn</span>
      <span class="hljs-attr">Runtime:</span> <span class="hljs-string">nodejs10.x</span>
      <span class="hljs-attr">Timeout:</span> <span class="hljs-number">10</span>

  <span class="hljs-attr">LambdaExecutionRole:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">"AWS::IAM::Role"</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">AssumeRolePolicyDocument:</span>
        <span class="hljs-attr">Version:</span> <span class="hljs-string">"2012-10-17"</span>
        <span class="hljs-attr">Statement:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">Effect:</span> <span class="hljs-string">"Allow"</span>
            <span class="hljs-attr">Principal:</span>
              <span class="hljs-attr">Service:</span>
                <span class="hljs-bullet">-</span> <span class="hljs-string">"lambda.amazonaws.com"</span>
            <span class="hljs-attr">Action:</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">"sts:AssumeRole"</span>
      <span class="hljs-attr">Policies:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">PolicyName:</span> <span class="hljs-string">"LambdaFunctionPolicy"</span>
          <span class="hljs-attr">PolicyDocument:</span>
            <span class="hljs-attr">Version:</span> <span class="hljs-string">'2012-10-17'</span>
            <span class="hljs-attr">Statement:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">Effect:</span> <span class="hljs-string">Allow</span>
              <span class="hljs-attr">Action:</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">logs:CreateLogGroup</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">logs:CreateLogStream</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">logs:PutLogEvents</span>
              <span class="hljs-attr">Resource:</span> <span class="hljs-string">"*"</span>

  <span class="hljs-attr">GraphQLApi:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">'AWS::ApiGateway::RestApi'</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">Name:</span> <span class="hljs-string">apollo-graphql-api</span>

  <span class="hljs-attr">GraphQLApiResource:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">'AWS::ApiGateway::Resource'</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">ParentId:</span> <span class="hljs-type">!GetAtt</span> <span class="hljs-string">GraphQLApi.RootResourceId</span>
      <span class="hljs-attr">RestApiId:</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">GraphQLApi</span>
      <span class="hljs-attr">PathPart:</span> <span class="hljs-string">'graphql'</span>

  <span class="hljs-attr">GraphQLApiMethod:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">'AWS::ApiGateway::Method'</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">RestApiId:</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">GraphQLApi</span>
      <span class="hljs-attr">ResourceId:</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">GraphQLApiResource</span>
      <span class="hljs-attr">AuthorizationType:</span> <span class="hljs-string">None</span>
      <span class="hljs-attr">HttpMethod:</span> <span class="hljs-string">POST</span>
      <span class="hljs-attr">Integration:</span>
        <span class="hljs-attr">Type:</span> <span class="hljs-string">AWS_PROXY</span>
        <span class="hljs-attr">IntegrationHttpMethod:</span> <span class="hljs-string">POST</span>
        <span class="hljs-attr">Uri:</span> <span class="hljs-type">!Sub</span> <span class="hljs-string">arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations</span>

  <span class="hljs-attr">GraphQLApiDeployment:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">'AWS::ApiGateway::Deployment'</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">RestApiId:</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">GraphQLApi</span>
      <span class="hljs-attr">StageName:</span> <span class="hljs-string">v1</span>
    <span class="hljs-attr">DependsOn:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">GraphQLApiResource</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">GraphQLApiMethod</span>

  <span class="hljs-attr">GraphQLApiPermission:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">'AWS::Lambda::Permission'</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">Action:</span> <span class="hljs-string">lambda:invokeFunction</span>
      <span class="hljs-attr">FunctionName:</span> <span class="hljs-type">!GetAtt</span> <span class="hljs-string">LambdaFunction.Arn</span>
      <span class="hljs-attr">Principal:</span> <span class="hljs-string">apigateway.amazonaws.com</span>
      <span class="hljs-attr">SourceArn:</span> <span class="hljs-type">!Sub</span> <span class="hljs-string">arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${GraphQLApi}/*</span>

<span class="hljs-attr">Outputs:</span>
  <span class="hljs-attr">ApiUrl:</span>
    <span class="hljs-attr">Description:</span> <span class="hljs-string">Invoke</span> <span class="hljs-string">url</span> <span class="hljs-string">of</span> <span class="hljs-string">API</span> <span class="hljs-string">Gateway</span> <span class="hljs-string">endpoint</span>
    <span class="hljs-attr">Value:</span> <span class="hljs-type">!Sub</span> <span class="hljs-string">https://${GraphQLApi}.execute-api.${AWS::Region}.amazonaws.com/v1/graphql</span>
</code></pre>
<p>I know a lot is happening in this template. Let’s examine the code step by step.</p>
<h2 id="heading-template-parameters">Template Parameters</h2>
<p>Firstly, we define some parameters that we use in the template. We can pass those variables as parameter overrides when deploying the CloudFormation Stack.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">Description:</span> <span class="hljs-string">GraphQL</span> <span class="hljs-string">server</span> <span class="hljs-string">on</span> <span class="hljs-string">AWS</span> <span class="hljs-string">lambda</span>

<span class="hljs-attr">Parameters:</span>
  <span class="hljs-attr">Version:</span>
    <span class="hljs-attr">Description:</span> <span class="hljs-string">Application</span> <span class="hljs-string">version</span> <span class="hljs-string">number</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">String</span>

  <span class="hljs-attr">BucketName:</span>
    <span class="hljs-attr">Description:</span> <span class="hljs-string">S3</span> <span class="hljs-string">bucket</span> <span class="hljs-string">name</span> <span class="hljs-string">where</span> <span class="hljs-string">the</span> <span class="hljs-string">source</span> <span class="hljs-string">code</span> <span class="hljs-string">lives</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">String</span>
</code></pre>
<h2 id="heading-lambda-function">Lambda Function</h2>
<p>We define our lambda function specifying the path from where it should pull the application code. This bucket is the same one we created earlier.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">LambdaFunction:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">AWS::Lambda::Function</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">Code:</span>
        <span class="hljs-attr">S3Bucket:</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">BucketName</span>
        <span class="hljs-attr">S3Key:</span> <span class="hljs-type">!Sub</span> <span class="hljs-string">dist-${Version}.zip</span>
      <span class="hljs-attr">Handler:</span> <span class="hljs-string">src/index.handler</span>
      <span class="hljs-attr">Description:</span> <span class="hljs-string">GraphQL</span> <span class="hljs-string">Apollo</span> <span class="hljs-string">Server</span>
      <span class="hljs-attr">Role:</span> <span class="hljs-type">!GetAtt</span> <span class="hljs-string">LambdaExecutionRole.Arn</span>
      <span class="hljs-attr">Runtime:</span> <span class="hljs-string">nodejs10.x</span>
      <span class="hljs-attr">Timeout:</span> <span class="hljs-number">10</span>
</code></pre>
<p>We want our Lambda function to be able to send application logs to AWS CloudWatch. Lambda requires special permissions to be able to write logs to CloudWatch. So we create a role that enables writing to CloudWatch and assign it to the Lambda function.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">LambdaExecutionRole:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">"AWS::IAM::Role"</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">AssumeRolePolicyDocument:</span>
        <span class="hljs-attr">Version:</span> <span class="hljs-string">"2012-10-17"</span>
        <span class="hljs-attr">Statement:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">Effect:</span> <span class="hljs-string">"Allow"</span>
            <span class="hljs-attr">Principal:</span>
              <span class="hljs-attr">Service:</span>
                <span class="hljs-bullet">-</span> <span class="hljs-string">"lambda.amazonaws.com"</span>
            <span class="hljs-attr">Action:</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">"sts:AssumeRole"</span>
      <span class="hljs-attr">Policies:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">PolicyName:</span> <span class="hljs-string">"LambdaFunctionPolicy"</span>
          <span class="hljs-attr">PolicyDocument:</span>
            <span class="hljs-attr">Version:</span> <span class="hljs-string">'2012-10-17'</span>
            <span class="hljs-attr">Statement:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">Effect:</span> <span class="hljs-string">Allow</span>
              <span class="hljs-attr">Action:</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">logs:CreateLogGroup</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">logs:CreateLogStream</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">logs:PutLogEvents</span>
              <span class="hljs-attr">Resource:</span> <span class="hljs-string">"*"</span>
</code></pre>
<h2 id="heading-api-gateway">API Gateway</h2>
<p>We also want an HTTP endpoint to invoke the lambda function. API Gateway can be used to create an HTTP endpoint. We can then configure API Gateway to proxy all incoming requests from the client to the Lambda function and send the response from Lambda back to the client.</p>
<p>Firstly, we create an API Gateway RestApi.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">GraphQLApi:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">'AWS::ApiGateway::RestApi'</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">Name:</span> <span class="hljs-string">apollo-graphql-api</span>
</code></pre>
<p>Then, we create an API Gateway Resource, which accepts requests at <code>/graphql</code>.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">GraphQLApiResource:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">'AWS::ApiGateway::Resource'</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">ParentId:</span> <span class="hljs-type">!GetAtt</span> <span class="hljs-string">GraphQLApi.RootResourceId</span>
      <span class="hljs-attr">RestApiId:</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">GraphQLApi</span>
      <span class="hljs-attr">PathPart:</span> <span class="hljs-string">'graphql'</span>
</code></pre>
<p>Next, we configure the Resource to accept POST requests by creating an API Gateway Method and then we integrate it with Lambda.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">GraphQLApiMethod:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">'AWS::ApiGateway::Method'</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">RestApiId:</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">GraphQLApi</span>
      <span class="hljs-attr">ResourceId:</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">GraphQLApiResource</span>
      <span class="hljs-attr">AuthorizationType:</span> <span class="hljs-string">None</span>
      <span class="hljs-attr">HttpMethod:</span> <span class="hljs-string">POST</span>
      <span class="hljs-attr">Integration:</span>
        <span class="hljs-attr">Type:</span> <span class="hljs-string">AWS_PROXY</span>
        <span class="hljs-attr">IntegrationHttpMethod:</span> <span class="hljs-string">POST</span>
        <span class="hljs-attr">Uri:</span> <span class="hljs-type">!Sub</span> <span class="hljs-string">arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations</span>
</code></pre>
<p>Finally, we create an API Gateway Deployment which deploys the API to the specified stage.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">GraphQLApiDeployment:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">'AWS::ApiGateway::Deployment'</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">RestApiId:</span> <span class="hljs-type">!Ref</span> <span class="hljs-string">GraphQLApi</span>
      <span class="hljs-attr">StageName:</span> <span class="hljs-string">v1</span>
    <span class="hljs-attr">DependsOn:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">GraphQLApiResource</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">GraphQLApiMethod</span>
</code></pre>
<h2 id="heading-lambda-api-gateway-permission">Lambda / API Gateway permission</h2>
<p>At this point, we have both the Lambda function and API gateway configured correctly. However, API Gateway needs special permission to invoke a Lambda function. We permit API Gateway to invoke Lambda by creating a Lambda Permission resource.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">GraphQLApiPermission:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">'AWS::Lambda::Permission'</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">Action:</span> <span class="hljs-string">lambda:invokeFunction</span>
      <span class="hljs-attr">FunctionName:</span> <span class="hljs-type">!GetAtt</span> <span class="hljs-string">LambdaFunction.Arn</span>
      <span class="hljs-attr">Principal:</span> <span class="hljs-string">apigateway.amazonaws.com</span>
      <span class="hljs-attr">SourceArn:</span> <span class="hljs-type">!Sub</span> <span class="hljs-string">arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${GraphQLApi}/*</span>
</code></pre>
<p>Finally, we export the API URL at the end of the template. We can use this URL to invoke calls to the Lambda.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">Outputs:</span>
  <span class="hljs-attr">ApiUrl:</span>
    <span class="hljs-attr">Description:</span> <span class="hljs-string">Invoke</span> <span class="hljs-string">url</span> <span class="hljs-string">of</span> <span class="hljs-string">API</span> <span class="hljs-string">Gateway</span> <span class="hljs-string">endpoint</span>
    <span class="hljs-attr">Value:</span> <span class="hljs-type">!Sub</span> <span class="hljs-string">https://${GraphQLApi}.execute-api.${AWS::Region}.amazonaws.com/v1/graphql</span>
</code></pre>
<h1 id="heading-deploy-cloudformation-stack-to-aws">Deploy CloudFormation stack to AWS</h1>
<p>Now that we have the CloudFormation template ready let’s use the AWS CLI command to deploy it to AWS.</p>
<p>Run the following command in your console. Make sure to update the BucketName to whatever the name of the bucket you created earlier is.</p>
<pre><code class="lang-bash">aws cloudformation deploy \
  --template-file ./cloudformation.yml \
  --stack-name apollo-server-lambda-nodejs \
  --parameter-overrides BucketName=lambda-deploy-asln Version=latest \
  --capabilities CAPABILITY_IAM
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/3-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Deploy CloudFormation stack to AWS</em></p>
<p>It might take some time to deploy the stack. Lambda function should be ready to start taking requests when the deployment finishes.</p>
<h1 id="heading-verify-api-gateway-and-lambda-are-working-as-expected">Verify API Gateway and Lambda are working as expected</h1>
<p>Now that we have deployed our CloudFormation Stack let us verify if everything is working as expected. We need the API Gateway URL to send a request to our Lambda Function. The API URL we exported in the CloudFormation template comes in handy here.</p>
<p>Run the following command to print the API URL in the command line.</p>
<pre><code class="lang-bash">aws cloudformation describe-stacks \
--stack-name=apollo-server-lambda-nodejs \
--query <span class="hljs-string">"Stacks[0].Outputs[?OutputKey=='ApiUrl'].OutputValue"</span> \
--output text
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/4-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Describe CloudFormation Stack</em></p>
<p>Now, use the <code>curl</code> command to invoke the API URL. You should get "Hello from Lambda" back from the server.</p>
<pre><code class="lang-bash">curl -d <span class="hljs-string">'{}'</span> https://o55ybz0sc5.execute-api.us-east-1.amazonaws.com/v1/graphql
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/5.png" alt="Image" width="600" height="400" loading="lazy">
<em>Invoke AWS Lambda</em></p>
<h1 id="heading-add-deploy-script-for-easier-deployment">Add deploy script for easier deployment</h1>
<p>You might have noticed that we ran a whole bunch of commands to package and deploy our application. It would be very tedious to have to run those commands every time we deploy the application. Let’s add a bash script to simplify this workflow.</p>
<p>Create a directory called <code>bin</code> at the root of the application and add a file named <code>deploy</code>.</p>
<pre><code class="lang-bash">mkdir bin 
touch bin/deploy
</code></pre>
<p>Before we can execute the script, we need to set correct file permissions. Let’s do that by running the following command.</p>
<pre><code class="lang-bash">chmod +x bin/deploy
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/6.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create deploy script</em></p>
<p>At this point, our directory structure should look like in the screenshot below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/7.png" alt="Image" width="600" height="400" loading="lazy">
<em>Current directory structure</em></p>
<p>Add the following code to the file.</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-built_in">set</span> -euo pipefail

OUTPUT_DIR=dist
CURRENT_DIR=$(<span class="hljs-built_in">pwd</span>)
ROOT_DIR=<span class="hljs-string">"<span class="hljs-subst">$( dirname <span class="hljs-string">"<span class="hljs-variable">${BASH_SOURCE[0]}</span>"</span> )</span>"</span>/..
APP_VERSION=$(date +%s)
STACK_NAME=apollo-server-lambda-nodejs

<span class="hljs-built_in">cd</span> <span class="hljs-variable">$ROOT_DIR</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"cleaning up old build.."</span>
[ -d <span class="hljs-variable">$OUTPUT_DIR</span> ] &amp;&amp; rm -rf <span class="hljs-variable">$OUTPUT_DIR</span>

mkdir dist

<span class="hljs-built_in">echo</span> <span class="hljs-string">"zipping source code.."</span>
zip -rq <span class="hljs-variable">$OUTPUT_DIR</span>/dist-<span class="hljs-variable">$APP_VERSION</span>.zip src node_modules package.json

<span class="hljs-built_in">echo</span> <span class="hljs-string">"uploading source code to s3.."</span>
aws s3 cp <span class="hljs-variable">$OUTPUT_DIR</span>/dist-<span class="hljs-variable">$APP_VERSION</span>.zip s3://<span class="hljs-variable">$S3_BUCKET</span>/dist-<span class="hljs-variable">$APP_VERSION</span>.zip

<span class="hljs-built_in">echo</span> <span class="hljs-string">"deploying application.."</span>
aws cloudformation deploy \
  --template-file <span class="hljs-variable">$ROOT_DIR</span>/cloudformation.yml \
  --stack-name <span class="hljs-variable">$STACK_NAME</span> \
  --parameter-overrides Version=<span class="hljs-variable">$APP_VERSION</span> BucketName=<span class="hljs-variable">$S3_BUCKET</span> \
  --capabilities CAPABILITY_IAM

<span class="hljs-comment"># Get the api url from output of cloudformation stack</span>
API_URL=$(
  aws cloudformation describe-stacks \
  --stack-name=<span class="hljs-variable">$STACK_NAME</span> \
  --query <span class="hljs-string">"Stacks[0].Outputs[?OutputKey=='ApiUrl'].OutputValue"</span> \
  --output text
)

<span class="hljs-built_in">echo</span> -e <span class="hljs-string">"\n<span class="hljs-variable">$API_URL</span>"</span>

<span class="hljs-built_in">cd</span> <span class="hljs-variable">$CURRENT_DIR</span>
</code></pre>
<p>OK, let’s break down what’s going on in this script.</p>
<p>We start by defining some variables. We generate the archive file inside the <code>dist</code> directory. We set the app version to the current timestamp at which the script runs. Using the timestamp, we can make sure that the version number is always unique and incremental.</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-built_in">set</span> -euo pipefail

OUTPUT_DIR=dist
CURRENT_DIR=$(<span class="hljs-built_in">pwd</span>)
ROOT_DIR=<span class="hljs-string">"<span class="hljs-subst">$( dirname <span class="hljs-string">"<span class="hljs-variable">${BASH_SOURCE[0]}</span>"</span> )</span>"</span>/..
APP_VERSION=$(date +%s)
STACK_NAME=apollo-server-lambda-nodejs
</code></pre>
<p>We then clean up any old builds and create a new <code>dist</code> directory.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"cleaning up old build.."</span>
[ -d <span class="hljs-variable">$OUTPUT_DIR</span> ] &amp;&amp; rm -rf <span class="hljs-variable">$OUTPUT_DIR</span>

mkdir dist
</code></pre>
<p>Then we run the zip command to archive the source code and its dependencies.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"zipping source code.."</span>
zip -rq <span class="hljs-variable">$OUTPUT_DIR</span>/dist-<span class="hljs-variable">$APP_VERSION</span>.zip src node_modules package.json
</code></pre>
<p>Next, we copy the zip file to the S3 bucket.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"uploading source code to s3.."</span>
aws s3 cp <span class="hljs-variable">$OUTPUT_DIR</span>/dist-<span class="hljs-variable">$APP_VERSION</span>.zip s3://<span class="hljs-variable">$S3_BUCKET</span>/dist-<span class="hljs-variable">$APP_VERSION</span>.zip
</code></pre>
<p>Then we deploy the CloudFormation stack.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"deploying application.."</span>
aws cloudformation deploy \
  --template-file <span class="hljs-variable">$ROOT_DIR</span>/cloudformation.yml \
  --stack-name <span class="hljs-variable">$STACK_NAME</span> \
  --parameter-overrides Version=<span class="hljs-variable">$APP_VERSION</span> BucketName=<span class="hljs-variable">$S3_BUCKET</span> \
  --capabilities CAPABILITY_IAM
</code></pre>
<p>Finally, we query the CloudFormation Stack to get the API URL from the CloudFormation Outputs and print it in the console.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Get the api url from output of cloudformation stack</span>
API_URL=$(
  aws cloudformation describe-stacks \
  --stack-name=<span class="hljs-variable">$STACK_NAME</span> \
  --query <span class="hljs-string">"Stacks[0].Outputs[?OutputKey=='ApiUrl'].OutputValue"</span> \
  --output text
)

<span class="hljs-built_in">echo</span> -e <span class="hljs-string">"\n<span class="hljs-variable">$API_URL</span>"</span>
</code></pre>
<h1 id="heading-deploy-to-aws-using-the-deploy-script">Deploy to AWS using the deploy script</h1>
<p>Let’s try out the deployment using the deploy script. The script expects the S3_Bucket variable to be present in the environment. Run the following command to run the deployment. When the deployment is successful, the script will output the API URL that we can use to invoke the lambda.</p>
<pre><code class="lang-bash">S3_BUCKET=lambda-deploy-asln ./bin/deploy
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/8.png" alt="Image" width="600" height="400" loading="lazy">
<em>Run the deploy script</em></p>
<p>To simplify this even further, let’s invoke it using yarn. Add the following in your <code>package.json</code>.</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
  <span class="hljs-attr">"deploy"</span>: <span class="hljs-string">"S3_BUCKET=lambda-deploy-asln ./bin/deploy"</span>
}
</code></pre>
<p>Hereafter we can simply run <code>yarn deploy</code> to initiate deployments.</p>
<h1 id="heading-improve-workflow-with-local-lambda-and-api-gateway">Improve workflow with local Lambda and API Gateway</h1>
<p>We frequently modified the application code while working on our application. Right now, deploying to AWS us-east-1 region takes me around 10 seconds. I am on a 40Mb/s upload speed internet connection.</p>
<p>Time to deploy becomes more significant as the size of the application grows. Having to wait 10 seconds or more to realize I have made a syntax error is not productive at all.</p>
<p>Let’s fix this by setting up the lambda function locally and invoke it using a local API Endpoint. AWS SAM CLI enables us to do just that. Follow the instruction on <a target="_blank" href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html">this page</a> to install it.</p>
<p>Once done, from the root of the project, run the following command.</p>
<pre><code class="lang-bash">sam <span class="hljs-built_in">local</span> start-api --template-file cloudformation.yml
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/9.png" alt="Image" width="600" height="400" loading="lazy">
<em>Start local development server</em></p>
<p>The local endpoint is now available at <a target="_blank" href="http://localhost:3000./">http://localhost:3000.</a> We can use this endpoint to send requests to our local Lambda.</p>
<p>Open another terminal and run the following command to send a request. You should see the response from our local Lambda function.</p>
<pre><code class="lang-bash">curl -d <span class="hljs-string">'{}'</span> http://localhost:3000/graphql
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/10.png" alt="Image" width="600" height="400" loading="lazy">
<em>Invoke local lambda function</em></p>
<p>Finally, add the following lines in the <code>scripts</code> section of the <code>package.json</code>.</p>
<pre><code class="lang-json"><span class="hljs-string">"dev"</span>: <span class="hljs-string">"sam local start-api --template-file cloudformation.yml"</span>
</code></pre>
<p>Hereafter we can run the <code>yarn dev</code> command to start the dev server.</p>
<h1 id="heading-set-up-the-graphql-server-in-lambda">Set up the GraphQL server in Lambda</h1>
<p>Without further talking, let’s jump right into the code and build the GraphQL server.</p>
<p>Start by installing the dependencies. We are using <a target="_blank" href="https://www.apollographql.com/docs/apollo-server/">Apollo Server</a> to build our GraphQL server. Apollo Server is an open-source implementation of GraphQL Server.</p>
<pre><code class="lang-bash">yarn add apollo-server-lambda graphql
</code></pre>
<p>Replace the content of <code>src/index.js</code> with the following code.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { ApolloServer, gql } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'apollo-server-lambda'</span>);

<span class="hljs-keyword">const</span> typeDefs = gql<span class="hljs-string">`
  type Query {
    user: User
  }

  type User {
    id: ID
    name: String
  }
`</span>;

<span class="hljs-keyword">const</span> resolvers = {
  <span class="hljs-attr">Query</span>: {
    <span class="hljs-attr">user</span>: <span class="hljs-function">() =&gt;</span> ({ <span class="hljs-attr">id</span>: <span class="hljs-number">123</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'John Doe'</span> })
  }
};

<span class="hljs-keyword">const</span> server = <span class="hljs-keyword">new</span> ApolloServer({ typeDefs, resolvers });

<span class="hljs-built_in">exports</span>.handler = server.createHandler();
</code></pre>
<p>Here, we define a schema which consists of a type User and a user query. We then define a resolver for the user query. For the sake of simplicity, the resolver returns a hardcoded user. Finally, we create a GraphQL handler and export it.</p>
<p>To perform queries to our GraphQL server, we need a GraphQL client. <a target="_blank" href="https://insomnia.rest/download/core/">Insomnia</a> is my favourite client. However, any other GraphQL client should be just fine.</p>
<p>Now, let’s run a query to ensure our server is working as expected.</p>
<p>Create a new GraphQL request in Insomnia.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/a.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create new GraphQL request</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/b.png" alt="Image" width="600" height="400" loading="lazy">
<em>Configure GraphQL request</em></p>
<p>Add the following query in the body and submit the query to <code>http://localhost:3000</code>. Assuming your dev server is still running, you should see the following response from the GraphQL server.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/c.png" alt="Image" width="600" height="400" loading="lazy">
<em>Perform GraphQL request to Local Server</em></p>
<p>Now that we've verified everything is working fine in the local server let’s run the following command to deploy the GraphQL server to AWS.</p>
<pre><code class="lang-bash">yarn deploy
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/d-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Deploy server to AWS</em></p>
<p>The API URL is outputted in the console once the deployment is complete. Replace the URL in Insomnia with the one from API Gateway. Rerun the query to see it resolve.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/e-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Perform GraphQL request to AWS Lambda</em></p>
<h1 id="heading-summary">Summary</h1>
<p>Congratulations, you have successfully deployed a GraphQL Server in AWS Lambda purely using CloudFormation. The server can receive GraphQL requests from the client and return the response accordingly. </p>
<p>We also set up the development environment for local development without adding many dependencies.</p>
<p>If you liked this tutorial, please share it with your network.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ AWS CloudFormation: Where to Find Help When You Need It ]]>
                </title>
                <description>
                    <![CDATA[ Staring at a plain, dumb command line prompt with no clue what to do with the AWS CLI next can be a humbling experience. And, in my experience at least, staring at the Management Console for AWS CloudFormation can be worse.  So let me offer you some ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/aws-cloudformation-where-to-find-help/</link>
                <guid isPermaLink="false">66b995ac65fc624db0255dcb</guid>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ aws cli ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cloudformation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Clinton ]]>
                </dc:creator>
                <pubDate>Mon, 18 May 2020 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/05/automation.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Staring at a plain, dumb command line prompt with no clue what to do with the AWS CLI next can be a humbling experience. And, in my experience at least, staring at the Management Console for AWS CloudFormation can be worse. </p>
<p>So let me offer you some quick "getting started" help based on part of the content in <a target="_blank" href="https://pluralsight.pxf.io/EMPE2">my latest Pluralsight course</a>. </p>
<p>First of all, if you're planning to manage your CloudFormation stacks through the AWS CLI rather than the Management Console, I discuss the basics in <a target="_blank" href="https://www.freecodecamp.org/news/aws-cli-tutorial-install-configure-understand-resource-environment/">this article</a>. Once that's all taken care of, you'll be ready for anything. </p>
<p>Start simple: </p>
<pre><code>$ aws s3 ls
<span class="hljs-number">2019</span><span class="hljs-number">-11</span><span class="hljs-number">-03</span> <span class="hljs-number">13</span>:<span class="hljs-number">16</span>:<span class="hljs-number">59</span> athena5905
<span class="hljs-number">2019</span><span class="hljs-number">-02</span><span class="hljs-number">-03</span> <span class="hljs-number">18</span>:<span class="hljs-number">01</span>:<span class="hljs-number">42</span> book<span class="hljs-number">-3939</span>
<span class="hljs-number">2014</span><span class="hljs-number">-07</span><span class="hljs-number">-01</span> <span class="hljs-number">18</span>:<span class="hljs-number">52</span>:<span class="hljs-number">32</span> elasticbeanstalk-ap-northeast<span class="hljs-number">-1</span><span class="hljs-number">-426397493112</span>
<span class="hljs-number">2014</span><span class="hljs-number">-08</span><span class="hljs-number">-28</span> <span class="hljs-number">16</span>:<span class="hljs-number">57</span>:<span class="hljs-number">49</span> elasticbeanstalk-us-east<span class="hljs-number">-1</span><span class="hljs-number">-426497493912</span>
<span class="hljs-number">2019</span><span class="hljs-number">-05</span><span class="hljs-number">-04</span> <span class="hljs-number">22</span>:<span class="hljs-number">17</span>:<span class="hljs-number">50</span> ltest236
<span class="hljs-number">2018</span><span class="hljs-number">-07</span><span class="hljs-number">-15</span> <span class="hljs-number">15</span>:<span class="hljs-number">52</span>:<span class="hljs-number">30</span> mybucket99688223
<span class="hljs-number">2017</span><span class="hljs-number">-07</span><span class="hljs-number">-25</span> <span class="hljs-number">17</span>:<span class="hljs-number">06</span>:<span class="hljs-number">43</span> nextcloud3239027
</code></pre><p>"aws" in that example tells your shell that you want what comes next to be handled by the AWS CLI. The "s3" I type next tells the CLI that I'll be using the S3 service - that's Amazon's Simple Storage Service. Finally, "ls" or "list" is the command I'd like to run against that service. </p>
<p>The CLI, using the account authentication variables that the configure tool added to my environment, will now hurry off and access my account, in this case retrieving the names of all of my buckets.</p>
<p>Predictably, you tell AWS that you're looking to work with CloudFormation using "cloudformation." If I just run that without specifying a command, I'll get an error message:</p>
<pre><code>aws cloudformation
<span class="hljs-attr">usage</span>: aws [options] &lt;command&gt; &lt;subcommand&gt; [&lt;subcommand&gt; ...] [parameters]
To see help text, you can run:

  aws help
  aws &lt;command&gt; help
  aws &lt;command&gt; &lt;subcommand&gt; help
aws: error: the following arguments are required: operation
</code></pre><p>But it's an important message, as it tells us how to access the inline documentation. Context-sensitive help is available at each layer. </p>
<p>See what happens if you add "help" after "cloudformation". You'll get a brief description and then a list of all the available subcommands. </p>
<pre><code>$ aws cloudformation help

CLOUDFORMATION()                                              CLOUDFORMATION()
NAME
       cloudformation -
DESCRIPTION
AWS  CloudFormation  allows you to create and manage AWS infrastructure deployments predictably and repeatedly. You can use AWS  CloudFormation to  leverage AWS products, such <span class="hljs-keyword">as</span> Amazon Elastic Compute Cloud, Amazon Elastic Block Store, Amazon Simple Notification Service,  Elastic  Load Balancing,  and Auto Scaling to build highly-reliable, highly scalable, cost-effective applications without creating or configuring the  underlying AWS infrastructure.
With  AWS  CloudFormation, you declare all <span class="hljs-keyword">of</span> your resources and dependencies <span class="hljs-keyword">in</span> a template  file.  The  template  defines  a  collection  <span class="hljs-keyword">of</span> resources  <span class="hljs-keyword">as</span>  a single unit called a stack. AWS CloudFormation creates and deletes all member resources <span class="hljs-keyword">of</span> the stack together and manages  all dependencies between the resources <span class="hljs-keyword">for</span> you.
For  more information about AWS CloudFormation, see the AWS CloudFormation Product Page.
Amazon CloudFormation makes use <span class="hljs-keyword">of</span> other  AWS  products.  If  you  need additional  technical information about a specific AWS product, you can find the product<span class="hljs-string">'s technical documentation at docs.aws.amazon.com.

AVAILABLE COMMANDS
       o cancel-update-stack
       o continue-update-rollback
       o create-change-set
       o create-stack
       o create-stack-set
       o delete-change-set
       o delete-stack
       o delete-stack-instances
       o delete-stack-set
       o deploy
       o describe-account-limits
       o describe-change-set
       o describe-stack-events
       o describe-stack-instance
       o describe-stack-resource
       o describe-stack-resources
       o describe-stack-set
       o describe-stack-set-operation
       o describe-stacks
       o estimate-template-cost
       o execute-change-set
       o get-stack-policy
[...]</span>
</code></pre><p>Now run the "describe-stacks" command. There are probably no live stacks in your account right now so you won't see any output. </p>
<p>But do that again, this time adding "help". This one will show you some options that'll let you filter or manipulate the data you get back. You could, for instance, point the CLI to one specific stack by using "--stack-name" followed by the name of an existing stack.</p>
<pre><code>$ aws cloudformation describe-stacks
$ aws cloudformation describe-stacks help
NAME
       describe-stacks -
DESCRIPTION
       Returns  the  description <span class="hljs-keyword">for</span> the specified stack; <span class="hljs-keyword">if</span> no stack name was specified, then it returns the description <span class="hljs-keyword">for</span> all the stacks created.
       NOTE:
          If the stack does not  exist,  an  AmazonCloudFormationException  is returned.
       See also: AWS API Documentation
       See <span class="hljs-string">'aws help'</span> <span class="hljs-keyword">for</span> descriptions <span class="hljs-keyword">of</span> <span class="hljs-built_in">global</span> parameters.
       describe-stacks  is  a  paginated  operation. Multiple API calls may be issued <span class="hljs-keyword">in</span> order to retrieve the entire data set  <span class="hljs-keyword">of</span>  results.  You  can disable pagination by providing the --no-paginate argument.  When using --output text and the --query argument on  a  paginated  response,  the --query  argument  must  extract data <span class="hljs-keyword">from</span> the results <span class="hljs-keyword">of</span> the following query expressions: Stacks

SYNOPSIS
            describe-stacks
          [--stack-name &lt;value&gt;]
          [--cli-input-json &lt;value&gt;]
          [--starting-token &lt;value&gt;]
          [--max-items &lt;value&gt;]
          [--generate-cli-skeleton &lt;value&gt;]

OPTIONS
       --stack-name (string)
          The name or the unique stack ID that is associated <span class="hljs-keyword">with</span>  the  stack,
          which are not always interchangeable:
[...]

$ aws cloudformation describe-stacks --stack-name myname
</code></pre><p>Those are tools that'll help you no matter what AWS service you're using. But looking specifically at CloudFormation, there are some valuable official collections of sample templates you should know about. JSON or YAML syntax being what they are, you probably won't want to start from an empty document. </p>
<p>Amazon itself has done a great job creating templates for us to work with. Your first stop should be the <a target="_blank" href="https://aws.amazon.com/cloudformation/resources/templates/">AWS CloudFormation Templates page</a>. Here you'll find links to snippets and specific application frameworks and some more cutting edge content. </p>
<p>But right now I'd like to draw your attention to one of the "sample templates" organized by AWS service (this code comes from one of the <a target="_blank" href="https://s3.us-west-2.amazonaws.com/cloudformation-templates-us-west-2/EC2InstanceWithSecurityGroupSample.template">Amazon EC2 examples</a>). </p>
<p>The template begins with a free form description that helpfully tells us what kind of stack this will generate. We're also told that we could customize the template by using an existing Elastic IP address instead of one that's automatically generated. </p>
<pre><code>{
  <span class="hljs-string">"AWSTemplateFormatVersion"</span> : <span class="hljs-string">"2010-09-09"</span>,

  <span class="hljs-string">"Description"</span> : <span class="hljs-string">"AWS CloudFormation Sample Template EC2InstanceWithSecurityGroupSample: Create an Amazon EC2 instance running the Amazon Linux AMI. The AMI is chosen based on the region in which the stack is run. This example creates an EC2 security group for the instance to give you SSH access. **WARNING** This template creates an Amazon EC2 instance. You will be billed for the AWS resources used if you create a stack from this template."</span>,
</code></pre><p>You'll need to pass in the name of an existing KeyPair from the current region in your AWS account so you'll be able to open remote SSH into the Linux instance that will be launched. You can alternatively pass along that value from the command line.</p>
<p>The Parameters section is also where you define the EC2 instance type. The default is t2.small, but we'd be allowed to either swap that value out for any of the other AllowedValues in this document, or override it from the command line. </p>
<pre><code>  <span class="hljs-string">"Parameters"</span> : {
    <span class="hljs-string">"KeyName"</span>: {
      <span class="hljs-string">"Description"</span> : <span class="hljs-string">"Name of an existing EC2 KeyPair to enable SSH access to the instance"</span>,
      <span class="hljs-string">"Type"</span>: <span class="hljs-string">"AWS::EC2::KeyPair::KeyName"</span>,
      <span class="hljs-string">"ConstraintDescription"</span> : <span class="hljs-string">"must be the name of an existing EC2 KeyPair."</span>
    },

    <span class="hljs-string">"InstanceType"</span> : {
      <span class="hljs-string">"Description"</span> : <span class="hljs-string">"WebServer EC2 instance type"</span>,
      <span class="hljs-string">"Type"</span> : <span class="hljs-string">"String"</span>,
      <span class="hljs-string">"Default"</span> : <span class="hljs-string">"t2.small"</span>,
</code></pre><p>If you scroll down through the Mappings section, we can see long lists of available hardware architectures and Amazon Machine Image identifiers for each region. </p>
<p>This is an optional section where you can insert your own non-standard values so, say, an image type would be launched based on a particular set of parameters - perhaps even a private AMI image. Such data is organized into key/value pairs. </p>
<pre><code>  <span class="hljs-string">"Mappings"</span> : {
    <span class="hljs-string">"AWSInstanceType2Arch"</span> : {
      <span class="hljs-string">"t1.micro"</span>    : { <span class="hljs-string">"Arch"</span> : <span class="hljs-string">"HVM64"</span>  },
      <span class="hljs-string">"t2.nano"</span>     : { <span class="hljs-string">"Arch"</span> : <span class="hljs-string">"HVM64"</span>  },
      <span class="hljs-string">"t2.micro"</span>    : { <span class="hljs-string">"Arch"</span> : <span class="hljs-string">"HVM64"</span>  },
</code></pre><p>The Resources section in this case defines your instance environment. The SecurityGroup, for instance, is configured to open the SSH port 22 but nothing else. The instance's public IP address is also associated with the new Elastic IP address that will be allocated. </p>
<pre><code>    <span class="hljs-string">"InstanceSecurityGroup"</span> : {
      <span class="hljs-string">"Type"</span> : <span class="hljs-string">"AWS::EC2::SecurityGroup"</span>,
      <span class="hljs-string">"Properties"</span> : {
        <span class="hljs-string">"GroupDescription"</span> : <span class="hljs-string">"Enable SSH access via port 22"</span>,
        <span class="hljs-string">"SecurityGroupIngress"</span> : [ {
          <span class="hljs-string">"IpProtocol"</span> : <span class="hljs-string">"tcp"</span>,
          <span class="hljs-string">"FromPort"</span> : <span class="hljs-string">"22"</span>,
          <span class="hljs-string">"ToPort"</span> : <span class="hljs-string">"22"</span>,
          <span class="hljs-string">"CidrIp"</span> : { <span class="hljs-string">"Ref"</span> : <span class="hljs-string">"SSHLocation"</span>}
        } ]
      }
    }
  },
</code></pre><p>One more important Amazon resource: <a target="_blank" href="https://aws.amazon.com/quickstart/?quickstart-all.sort-by=item.additionalFields.updateDate&amp;quickstart-all.sort-order=desc">Quick Starts</a>. Strictly speaking the pre-built infrastructure stacks that are provided here to help you create more complex cloud deployments aren't directly related to CloudFormation. They were provided by third-party companies to simplify the process of building their infrastructure in within the AWS platform. </p>
<p>But the fact is that each one starts with its own unique CloudFormation template. Clicking through to look at actual examples will often lead you to the stack source code templates within a GitHub repo. <a target="_blank" href="https://github.com/aws-quickstart/quickstart-hashicorp-consul">This example</a> shows us the tools you'd need to fire up a HashiCorp Console:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/Screenshot-from-2020-05-17-13-06-37.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Either way, feel free to use these templates as learning tools - or browse through the selection to see if there's a stack there that happens to fit your needs.</p>
<p><em>There's much more administration goodness in the form of books, courses, and articles available at my <a target="_blank" href="https://bootstrap-it.com/">bootstrap-it.com</a>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ AWS CLI Tutorial – How to Install, Configure, and Use AWS CLI to Understand Your Resource Environment ]]>
                </title>
                <description>
                    <![CDATA[ How to get exactly the account and environment information you need to manage your AWS account using just the AWS CLI Installing the AWS CLI is actually quite simple. The best way to get it done is to head over to the AWS installation guide and follo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/aws-cli-tutorial-install-configure-understand-resource-environment/</link>
                <guid isPermaLink="false">66b995a977e922646120d721</guid>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ aws cli ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Cloud Computing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cloudformation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Clinton ]]>
                </dc:creator>
                <pubDate>Mon, 11 May 2020 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/05/keyboard.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><em>How to get exactly the account and environment information you need to manage your AWS account using just the AWS CLI</em></p>
<p>Installing the AWS CLI is actually quite simple. The best way to get it done is to head over to the <a target="_blank" href="https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html">AWS installation guide</a> and follow instructions for your OS. </p>
<p>Right now they're pushing us towards version 2 of the CLI and I haven't seen any reason not to go along. I'm working with Linux so that's where I'd head next.</p>
<p>To get it done, I'll paste the curl command from the Amazon page into my Linux shell that'll download the package and write it to a local zip file, which I'll then unzip. That'll create a new directory called aws that'll contain a install script, which I can run using sudo to get admin privileges. I'll run aws --version to confirm everything worked as it was supposed to.</p>
<pre><code>curl <span class="hljs-string">"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"</span> -o <span class="hljs-string">"awscliv2.zip"</span>
unzip awscliv2.zip
ls aws
sudo ./aws/install
aws --version
</code></pre><p>The next step will require one quick trip to the management console. You see, to authenticate the CLI to your account you'll need a valid access key. Now, the CLI has a "create-access-key" command that'll generate a new key, but that's only possible once I've authenticated. I'm sure you understand the problem with that.</p>
<p>You access the security credentials page from the drop-down account menu at the top of any page on the console. With your credentials in hand, you can run "aws configure." You'll be prompted to enter your access key ID and the secret key itself. If you like you can then choose a default AWS region and output format. The format won't be an issue so I'll leave it as default.</p>
<pre><code>aws configure
</code></pre><p>That's it. Just to confirm it all worked, I'll list all the S3 buckets in my account. With that, we'll all set to get down to work in the next clip.</p>
<pre><code>aws s3 ls
</code></pre><p>You may already know that Amazon's CloudFormation service exists to let you manage your application infrastructure by organising it into stacks of your AWS account resources.</p>
<p>The CloudFormation templates that define those stacks can be shared, edited, and launched anywhere, giving you predictable and reliable cloud application environments wherever and whenever you need them. </p>
<p>You may also know that you can mange your CloudFormation stacks both through the AWS Management Console and, as I discuss in my <a target="_blank" href="https://pluralsight.pxf.io/EMPE2">new Pluralsight course, Create and Manage Stacks with AWS CloudFormation Using the Command Line Interface</a>, using the AWS CLI.</p>
<p>If you do choose to go with the AWS CLI – something I highly recommend – you'll need a way to gather key information about other account resources. But how you're expected to get that information through the CLI might, at first, not appear so obvious.</p>
<p>To show you what I mean, let's experiment with a more complex stack using a template that comes from the AWS documentation samples.</p>
<p>The <a target="_blank" href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/sample-templates-appframeworks-us-east-1.html">Application Frameworks template set</a> includes a template for auto scaled Linux servers that will come pre-provisioned with the Apache web server and the PHP scripting language, and a connection to a Multi-AZ RDS database instance running the MySQL database engine.</p>
<p>You can click View from that AWS documentation page and take a look at the template itself. There you'll see Parameters sections defining the VPC and subnets into which your instance will launch and the MySQL database name, user, and password. </p>
<p>It's critical that all the right services know those details because, otherwise, they won't be able to talk to each other. We'll have to figure out a way to add those values. To get things going, you can simply click to view the template (<a target="_blank" href="https://s3.amazonaws.com/cloudformation-templates-us-east-1/LAMP_Multi_AZ.template">which you can see here</a>), and copy the contents, pasting it into a new JSON file on your local machine.</p>
<p>You use the CLI to fire up a Cloudformation stack using the create-stack command. The command, however, takes a few arguments to pass important information. This minimal example shows you how to point CloudFormation to your JSON template file, a name to assign to your stack, and a valid SSH key so I'll be able to log into the instance it creates.</p>
<pre><code>aws cloudformation create-stack \
  --template-body file:<span class="hljs-comment">//lamp-as.json \</span>
  --stack-name lamp \
  --parameters \
  ParameterKey=KeyName,ParameterValue=mykey
</code></pre><p>The problem is that, if you were to run that command against the template in your JSON document, it would fail. That's because, as you'll no doubt remember from looking through the template, there are some extra parameters that need satisfying. Specifically, we'll need references to a VPC and to two subnets - and because this is a multi-availability-zone deployment, they'll need to be in different zones.</p>
<p>How will that work? It's the AWS CLI to the rescue. Need a VPC ID? Keeping in mind that VPCs are EC2 objects, you can run aws ec2 describe-vpcs and all the data you'll need - including the VPC ID - will magically appear. And subnets? Well more of the same, obviously. Just copy subnet IDs for any two of the subnets that will appear and you're in business.</p>
<pre><code>aws ec2 describe-vpcs
aws ec2 describe-subnets
</code></pre><p>Now let's put all that information together into our new version of the create-stack command. You'll need to be careful with this as there are some nasty gotchas in the syntax.</p>
<pre><code>aws cloudformation create-stack \
  --template-body file:<span class="hljs-comment">//lamp-as.json \</span>
  --stack-name lamp-<span class="hljs-keyword">as</span> \
  --parameters \
  ParameterKey=KeyName,ParameterValue=mykey \
  ParameterKey=VpcId,ParameterValue=vpc<span class="hljs-number">-1</span>ffbc964 \
  ParameterKey=Subnets,ParameterValue=\<span class="hljs-string">'subnet-0e170b31,subnet-52d6117c\' \
  ParameterKey=DBUser,ParameterValue=myadmin \
  ParameterKey=DBPassword,ParameterValue=mypass23</span>
</code></pre><p>The first new parameter is VPC-ID. But make sure you get the case right: using an uppercase D in Id will cause the whole thing to fail. I don't know why they make things so difficult to live with, but that's what we've got.</p>
<p>The next one is even more delicate. Since we need two subnets, we'll need to enter them on a single line separated by a comma - but no space. However, we'll also need to enclose the string within single apostrophes. But the CLI can't read apostrophes just like that, so we'll need to escape them using backslashes. Got that? </p>
<p>I'll also add those two database parameters: DBUser and my ultra secret, super cryptic DBPassword. Will it work? You betcha. But don't tell anyone how many times I had to try this without you watching before I got it right. Remember: failure is your friend.</p>
<p>When our stack is good and launched (which could take as long as half an hour), running describe-stacks will give us our website URL.</p>
<pre><code>aws cloudformation describe-stacks
</code></pre><p>But that's not the whole story.  I'm going to use another aws ec2 command - describe-instances this time - to get some information about the EC2 instances that were launched as part of this stack. This one will filter results, restricting output to only those instances that are currently running. </p>
<pre><code>aws ec2 describe-instances \
  --filters Name=instance-state-name,Values=running \
  --query <span class="hljs-string">'Reservations[*].Instances[*].{Instance:InstanceId,PublicIPAddress:PublicIpAddress}'</span>
</code></pre><p>I happen to have no other instances running in this region, so only the CloudFormation instances will show up. Now I use --query to further filter the output to give me only the Instance IDs and public IP addresses of those instances. There are, as you would expect, exactly two running.</p>
<p>Just a taste - and most of it related specifically to CloudFormation - but I think you get the idea of how information gathering works using the AWS CLI.</p>
<p><em>There's much more administration goodness in the form of books, courses, and articles available at my <a target="_blank" href="https://bootstrap-it.com">bootstrap-it.com</a>.</em> </p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
