<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chris Straw</title>
    <description>The latest articles on DEV Community by Chris Straw (@cstraw).</description>
    <link>https://dev.to/cstraw</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F610912%2Fe97d6f6d-f1fa-481e-96f0-39d73d4378dc.jpeg</url>
      <title>DEV Community: Chris Straw</title>
      <link>https://dev.to/cstraw</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cstraw"/>
    <language>en</language>
    <item>
      <title>File types, purposes, and directory skeleton - Part 5 of Implementing a RESTful API on AWS</title>
      <dc:creator>Chris Straw</dc:creator>
      <pubDate>Thu, 06 May 2021 21:16:38 +0000</pubDate>
      <link>https://dev.to/cstraw/file-types-purposes-and-directory-skeleton-no2</link>
      <guid>https://dev.to/cstraw/file-types-purposes-and-directory-skeleton-no2</guid>
      <description>&lt;p&gt;Quick recap: this is a soup to nuts series covering implementing a full-featured REST API on AWS from the perspective of a long-time infrastructure engineer with a historical preference for Java-based solutions.&lt;/p&gt;

&lt;p&gt;In the previous parts of this series, we (a) set up our build environment; (b) registered our AWS account; (c) created our Administrative users; and (d) stubbed out our default Serverless service.  &lt;/p&gt;

&lt;p&gt;We'll now cover (I) the various file types we will be using; and (II) our directory structure; while endeavoring to explain the design decisions behind why we are proceeding in the way we are.&lt;/p&gt;

&lt;h1&gt;
  
  
  I. Various File Types
&lt;/h1&gt;

&lt;h2&gt;
  
  
  A. Serverless / CloudFormation Configuration Files
&lt;/h2&gt;

&lt;p&gt;At its core, Serverless Framework is an extremely powerful javascript module that translates a YAML configuration file named &lt;code&gt;serverless.yml&lt;/code&gt; into vendor-specific cloud service commands.  In the case of AWS, these are AWS CloudFormation commands such as &lt;code&gt;create-function&lt;/code&gt; for AWS Lambda or &lt;code&gt;create-table&lt;/code&gt; for DynamoDB.&lt;/p&gt;

&lt;p&gt;But why introduce this intermediate Serverless Framework instead of just using the AWS CLI?  A number of reasons, including: (1) the veneer of avoiding vendor lock-in; (2) the additional variables; and (3) the ability to develop and debug our code offline without using AWS resources.  &lt;/p&gt;

&lt;p&gt;With that, let's look at the default &lt;code&gt;serverless.yml&lt;/code&gt; file that we created in the last part of this series.  Switch to your working directory and type &lt;code&gt;code serverless.yml&lt;/code&gt; to open the file in VS Code. &lt;/p&gt;

&lt;h3&gt;
  
  
  1) Initial Serverless.yml Skeleton
&lt;/h3&gt;

&lt;p&gt;
  Full contents of the default serverless.yml
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Welcome to Serverless!&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# This file is the main config file for your service.&lt;/span&gt;
&lt;span class="c1"&gt;# It's very minimal at this point and uses default values.&lt;/span&gt;
&lt;span class="c1"&gt;# You can always add more config options for more control.&lt;/span&gt;
&lt;span class="c1"&gt;# We've included some commented out config examples here.&lt;/span&gt;
&lt;span class="c1"&gt;# Just uncomment any of them to get that config option.&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# For full config options, check the docs:&lt;/span&gt;
&lt;span class="c1"&gt;#    docs.serverless.com&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# Happy Coding!&lt;/span&gt;

&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myrestproject&lt;/span&gt;
&lt;span class="c1"&gt;# app and org for use with dashboard.serverless.com&lt;/span&gt;
&lt;span class="c1"&gt;#app: your-app-name&lt;/span&gt;
&lt;span class="c1"&gt;#org: your-org-name&lt;/span&gt;

&lt;span class="c1"&gt;# You can pin your service to only deploy with a specific Serverless version&lt;/span&gt;
&lt;span class="c1"&gt;# Check out our docs for more details&lt;/span&gt;
&lt;span class="na"&gt;frameworkVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs12.x&lt;/span&gt;
  &lt;span class="na"&gt;lambdaHashingVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20201221&lt;/span&gt;

&lt;span class="c1"&gt;# you can overwrite defaults here&lt;/span&gt;
&lt;span class="c1"&gt;#  stage: dev&lt;/span&gt;
&lt;span class="c1"&gt;#  region: us-east-1&lt;/span&gt;

&lt;span class="c1"&gt;# you can add statements to the Lambda function's IAM Role here&lt;/span&gt;
&lt;span class="c1"&gt;#  iamRoleStatements:&lt;/span&gt;
&lt;span class="c1"&gt;#    - Effect: "Allow"&lt;/span&gt;
&lt;span class="c1"&gt;#      Action:&lt;/span&gt;
&lt;span class="c1"&gt;#        - "s3:ListBucket"&lt;/span&gt;
&lt;span class="c1"&gt;#      Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ]  }&lt;/span&gt;
&lt;span class="c1"&gt;#    - Effect: "Allow"&lt;/span&gt;
&lt;span class="c1"&gt;#      Action:&lt;/span&gt;
&lt;span class="c1"&gt;#        - "s3:PutObject"&lt;/span&gt;
&lt;span class="c1"&gt;#      Resource:&lt;/span&gt;
&lt;span class="c1"&gt;#        Fn::Join:&lt;/span&gt;
&lt;span class="c1"&gt;#          - ""&lt;/span&gt;
&lt;span class="c1"&gt;#          - - "arn:aws:s3:::"&lt;/span&gt;
&lt;span class="c1"&gt;#            - "Ref" : "ServerlessDeploymentBucket"&lt;/span&gt;
&lt;span class="c1"&gt;#            - "/*"&lt;/span&gt;

&lt;span class="c1"&gt;# you can define service wide environment variables here&lt;/span&gt;
&lt;span class="c1"&gt;#  environment:&lt;/span&gt;
&lt;span class="c1"&gt;#    variable1: value1&lt;/span&gt;

&lt;span class="c1"&gt;# you can add packaging information here&lt;/span&gt;
&lt;span class="c1"&gt;#package:&lt;/span&gt;
&lt;span class="c1"&gt;#  include:&lt;/span&gt;
&lt;span class="c1"&gt;#    - include-me.js&lt;/span&gt;
&lt;span class="c1"&gt;#    - include-me-dir/**&lt;/span&gt;
&lt;span class="c1"&gt;#  exclude:&lt;/span&gt;
&lt;span class="c1"&gt;#    - exclude-me.js&lt;/span&gt;
&lt;span class="c1"&gt;#    - exclude-me-dir/**&lt;/span&gt;

&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;handler.hello&lt;/span&gt;
&lt;span class="c1"&gt;#    The following are a few example events you can configure&lt;/span&gt;
&lt;span class="c1"&gt;#    NOTE: Please make sure to change your handler code to work with those events&lt;/span&gt;
&lt;span class="c1"&gt;#    Check the event documentation for details&lt;/span&gt;
&lt;span class="c1"&gt;#    events:&lt;/span&gt;
&lt;span class="c1"&gt;#      - httpApi:&lt;/span&gt;
&lt;span class="c1"&gt;#          path: /users/create&lt;/span&gt;
&lt;span class="c1"&gt;#          method: get&lt;/span&gt;
&lt;span class="c1"&gt;#      - websocket: $connect&lt;/span&gt;
&lt;span class="c1"&gt;#      - s3: ${env:BUCKET}&lt;/span&gt;
&lt;span class="c1"&gt;#      - schedule: rate(10 minutes)&lt;/span&gt;
&lt;span class="c1"&gt;#      - sns: greeter-topic&lt;/span&gt;
&lt;span class="c1"&gt;#      - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000&lt;/span&gt;
&lt;span class="c1"&gt;#      - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx&lt;/span&gt;
&lt;span class="c1"&gt;#      - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx&lt;/span&gt;
&lt;span class="c1"&gt;#      - iot:&lt;/span&gt;
&lt;span class="c1"&gt;#          sql: "SELECT * FROM 'some_topic'"&lt;/span&gt;
&lt;span class="c1"&gt;#      - cloudwatchEvent:&lt;/span&gt;
&lt;span class="c1"&gt;#          event:&lt;/span&gt;
&lt;span class="c1"&gt;#            source:&lt;/span&gt;
&lt;span class="c1"&gt;#              - "aws.ec2"&lt;/span&gt;
&lt;span class="c1"&gt;#            detail-type:&lt;/span&gt;
&lt;span class="c1"&gt;#              - "EC2 Instance State-change Notification"&lt;/span&gt;
&lt;span class="c1"&gt;#            detail:&lt;/span&gt;
&lt;span class="c1"&gt;#              state:&lt;/span&gt;
&lt;span class="c1"&gt;#                - pending&lt;/span&gt;
&lt;span class="c1"&gt;#      - cloudwatchLog: '/aws/lambda/hello'&lt;/span&gt;
&lt;span class="c1"&gt;#      - cognitoUserPool:&lt;/span&gt;
&lt;span class="c1"&gt;#          pool: MyUserPool&lt;/span&gt;
&lt;span class="c1"&gt;#          trigger: PreSignUp&lt;/span&gt;
&lt;span class="c1"&gt;#      - alb:&lt;/span&gt;
&lt;span class="c1"&gt;#          listenerArn: arn:aws:elasticloadbalancing:us-east-1:XXXXXX:listener/app/my-load-balancer/50dc6c495c0c9188/&lt;/span&gt;
&lt;span class="c1"&gt;#          priority: 1&lt;/span&gt;
&lt;span class="c1"&gt;#          conditions:&lt;/span&gt;
&lt;span class="c1"&gt;#            host: example.com&lt;/span&gt;
&lt;span class="c1"&gt;#            path: /hello&lt;/span&gt;

&lt;span class="c1"&gt;#    Define function environment variables here&lt;/span&gt;
&lt;span class="c1"&gt;#    environment:&lt;/span&gt;
&lt;span class="c1"&gt;#      variable2: value2&lt;/span&gt;

&lt;span class="c1"&gt;# you can add CloudFormation resource templates here&lt;/span&gt;
&lt;span class="c1"&gt;#resources:&lt;/span&gt;
&lt;span class="c1"&gt;#  Resources:&lt;/span&gt;
&lt;span class="c1"&gt;#    NewResource:&lt;/span&gt;
&lt;span class="c1"&gt;#      Type: AWS::S3::Bucket&lt;/span&gt;
&lt;span class="c1"&gt;#      Properties:&lt;/span&gt;
&lt;span class="c1"&gt;#        BucketName: my-new-bucket&lt;/span&gt;
&lt;span class="c1"&gt;#  Outputs:&lt;/span&gt;
&lt;span class="c1"&gt;#     NewOutput:&lt;/span&gt;
&lt;span class="c1"&gt;#       Description: "Description for the output"&lt;/span&gt;
&lt;span class="c1"&gt;#       Value: "Some output value"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;p&gt;You'll see that most of the default file consists of commented out formatted examples, with only 9 lines of actual configuration in YAML format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myrestproject&lt;/span&gt;
&lt;span class="na"&gt;frameworkVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs12.x&lt;/span&gt;
  &lt;span class="na"&gt;lambdaHashingVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20201221&lt;/span&gt;
&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;handler.hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each of these is a key/value pair.  An important point to remember is that the key names, like variable names, will be constants that cannot be dynamically set.  Rather, the names of the constants will--depending on the situation--be set by either: (a) serverless; (b) AWS; or (c) you the end user.  The values, on the other hand, will often be dynamically set.  &lt;/p&gt;

&lt;p&gt;Let's cover each of the nine functional lines in the default configuration file:&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myrestproject&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  a) service
&lt;/h4&gt;

&lt;p&gt;The value of the &lt;code&gt;service&lt;/code&gt; key will be used to generate the name your AWS deployment bundle.  AWS refers to these--unsurprisingly--as a 'stack'.  &lt;/p&gt;

&lt;p&gt;Serverless follows the recommended practice of appending a development stage modifier to the base stack name.  By default, this value is 'dev', giving us a full stack name of 'myrestproject-dev'.&lt;/p&gt;

&lt;p&gt;You can see the list of deployed stacks through both the web UI (be sure your region in the top right is set correctly):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://console.aws.amazon.com/cloudformation/"&gt;https://console.aws.amazon.com/cloudformation/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and the AWS CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws cloudformation list-stacks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;








&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;frameworkVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  b) frameworkVersion
&lt;/h4&gt;

&lt;p&gt;The version of the Serverless Framework.  The supplied value here is pinned to any version 2 of the Framework.  No need to change it.&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs12.x&lt;/span&gt;
  &lt;span class="na"&gt;lambdaHashingVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20201221&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  c) provider
&lt;/h4&gt;

&lt;p&gt;Provider is our first structured entry.  All of our vendor-specific entries will be children below this key.  There are a number of additional ones, but we are only covering the basic ones for now:&lt;/p&gt;

&lt;h5&gt;
  
  
  i) name
&lt;/h5&gt;

&lt;p&gt;The name of our cloud service vendor: 'aws'.  Other options would include 'azure' or whatever that thing is that Google offers.&lt;/p&gt;

&lt;h5&gt;
  
  
  ii) runtime
&lt;/h5&gt;

&lt;p&gt;The default version of Node.js needed to run our functions.  (We can override this on a per-function basis on the off-chance it is necessary).  AWS claims to support Node.js version 14, but at least some features were not working correctly last time I checked in March 2021 (e.g. nullish coalescing).  Go ahead and keep it as &lt;code&gt;nodejs12.x&lt;/code&gt; for the time being.&lt;/p&gt;

&lt;h5&gt;
  
  
  iii) lambdaHashingVersion
&lt;/h5&gt;

&lt;p&gt;The Serverless Framework occasionally deprecates and changes underlying functionality.  In this instance, they apparently are transitioning the underlying hash function used to determine if a function has been altered.  Since we are just starting out, we should switch right now to what will be the default in Serverless Framework 3.0 by setting this value to &lt;code&gt;20201221&lt;/code&gt; as indicated in the default serverless file.&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;handler.hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  d) functions
&lt;/h4&gt;

&lt;p&gt;Back up to the top level, &lt;code&gt;functions&lt;/code&gt; contains a structured description of our lambda functions.  Each function will be its own entry.&lt;/p&gt;

&lt;h5&gt;
  
  
  i) hello
&lt;/h5&gt;

&lt;p&gt;This is a developer-selected name used for referencing the function elsewhere in our serverless.yml and AWS CloudFormation configuration files.  Here, the provided name is &lt;code&gt;hello&lt;/code&gt;, but it could be &lt;code&gt;yolo&lt;/code&gt; or &lt;code&gt;mydogspot&lt;/code&gt; or something else, subject to the caveat noted before that key names are required to be constants (e.g. it cannot be named &lt;code&gt;${self.custom.myLambdaName}&lt;/code&gt;).&lt;/p&gt;

&lt;h6&gt;
  
  
  (1) handler
&lt;/h6&gt;

&lt;p&gt;The javascript function that will process executions of this lambda function.  The format is &amp;lt;filename&amp;gt;.&amp;lt;function name&amp;gt; (e.g. handler.hello points to the hello function in handler.js within the base directory, whereas ./src/aws/AWSController.findOne points at the findOne function in AWSController.js within the ./src/aws/ directory).&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Modified Serverless.yml
&lt;/h3&gt;

&lt;p&gt;With this basic understanding of our serverless.yml configuration file out of the way, let's start putting together a working REST template.&lt;/p&gt;

&lt;p&gt;
  Full contents of the modified serverless.yml
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app and org for integration with dashboard.serverless.com&lt;/span&gt;
&lt;span class="c1"&gt;# Note that using this will cause Serverless to inject a logging handler proxy&lt;/span&gt;
&lt;span class="c1"&gt;# before the calls to your lambda functions, resulting in the renaming of your handler&lt;/span&gt;
&lt;span class="c1"&gt;# in the AWS interface&lt;/span&gt;
&lt;span class="c1"&gt;#org: &amp;lt;your_org_name_here&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#app: &amp;lt;your_dashboard_appname_here&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;# name of our microservice&lt;/span&gt;
&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.resourceName}Service&lt;/span&gt;

&lt;span class="na"&gt;frameworkVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=2.0'&lt;/span&gt;
&lt;span class="na"&gt;variablesResolutionMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20210219&lt;/span&gt;

&lt;span class="c1"&gt;#############################################################################################&lt;/span&gt;
&lt;span class="c1"&gt;# CUSTOM VARIABLES - all variables necessary to get up and running should be in this section&lt;/span&gt;
&lt;span class="c1"&gt;#############################################################################################&lt;/span&gt;
&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;resourceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;teams&lt;/span&gt;
  &lt;span class="c1"&gt;# Email address of primary contact; embedded into internal "Tags" to aid in&lt;/span&gt;
  &lt;span class="c1"&gt;# internal maintenance&lt;/span&gt;
  &lt;span class="na"&gt;primaryContact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;YOUR EMAIL ADDRESS&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;YOUR AWS REGION&amp;gt;&lt;/span&gt;

  &lt;span class="na"&gt;dynamodb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# For tables, I have adopted a naming convention of &amp;lt;SERVICE&amp;gt;-Table-&amp;lt;EntityName&amp;gt;-&amp;lt;Stage&amp;gt;; e.g. SportsApp-Table-Players-dev&lt;/span&gt;
    &lt;span class="na"&gt;resourceTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:service}-Table-${self:custom.resourceName}-${self:provider.stage}&lt;/span&gt;
    &lt;span class="c1"&gt;# For indexes, I have adopted a naming convention of &amp;lt;SERVICE&amp;gt;-TableIdx-&amp;lt;EntityName&amp;gt;-&amp;lt;Constraint/SearchKey&amp;gt;-&amp;lt;Stage&amp;gt;; e.g. SportsApp-TableIdx-Players-LastName-dev&lt;/span&gt;
    &lt;span class="na"&gt;resourceTableIdx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:service}-TableIdx-${self:custom.resourceName}-Name-${self:provider.stage}&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="c1"&gt;# AWS claims they support NodeJS14, but as of March 2021, certain Node14 features don't appear to function correctly, e.g. nullish coalescing&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs14.x&lt;/span&gt;
  &lt;span class="na"&gt;lambdaHashingVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20201221&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;  
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.region}&lt;/span&gt;

  &lt;span class="na"&gt;apiGateway&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# setting required for the transition from Serverless Framework 2.0 to 3.0+&lt;/span&gt;
    &lt;span class="na"&gt;shouldStartNameWithService&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

    &lt;span class="c1"&gt;# we can have AWS API Gateway validate incoming requests prior to sending it to our lambda,&lt;/span&gt;
    &lt;span class="c1"&gt;# saving us the processing cost for malformed requests&lt;/span&gt;
    &lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;schemas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;resource-create-model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.resourceName}CreateModel&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(src/schema/createResourceSchema.json)}&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Model&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;validation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;creating&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;${self:custom.resourceName}"&lt;/span&gt;

  &lt;span class="c1"&gt;# Environment variables our Javascript code relies on&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:provider.stage}&lt;/span&gt;
    &lt;span class="na"&gt;TABLE_NAME_TEAM&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.dynamodb.resourceTable}&lt;/span&gt;
    &lt;span class="na"&gt;TABLE_IDX_TEAM_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.dynamodb.resourceTableIdx}&lt;/span&gt;

  &lt;span class="c1"&gt;# Base IAm role that the lambdas will execute with&lt;/span&gt;
  &lt;span class="na"&gt;iam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./resources/aws/iam/LambdaRole.yml)}&lt;/span&gt;

&lt;span class="c1"&gt;# Serverless Framework plugins&lt;/span&gt;
&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# support for typescript&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-plugin-typescript&lt;/span&gt;

  &lt;span class="c1"&gt;# Allows us to use a local instance during development, eliminating need&lt;/span&gt;
  &lt;span class="c1"&gt;# to publish to cloud to see changes to functions and allowing use of a debugger&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-offline&lt;/span&gt;

&lt;span class="c1"&gt;# define all of our REST microservice endpoints&lt;/span&gt;
&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./resources/aws/RESTFunctions.yml)}&lt;/span&gt;

&lt;span class="c1"&gt;# Settings relating to how our module will be bundled for execution&lt;/span&gt;
&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Don't include node_modules like typescript and unit testing when&lt;/span&gt;
  &lt;span class="c1"&gt;# publishing our bundle to the cloud; results in notably smaller upload bundle&lt;/span&gt;
  &lt;span class="na"&gt;excludeDevDependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Values that we want to export out of this service for use in other services&lt;/span&gt;
  &lt;span class="c1"&gt;# Including an export name pollutes the global namespace and is only necessary&lt;/span&gt;
  &lt;span class="c1"&gt;# when you don't know this Stack's name, as you can otherwise obtain the value&lt;/span&gt;
  &lt;span class="c1"&gt;# using the key name you chose below, e.g. 'ApiGatewayRestApiExport'&lt;/span&gt;
  &lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ApiGatewayRestApiExport&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ApiGatewayRestApi'&lt;/span&gt;
&lt;span class="c1"&gt;#      Export:&lt;/span&gt;
&lt;span class="c1"&gt;#        Name: ${self:service}-${self:provider.stage}-api&lt;/span&gt;

  &lt;span class="c1"&gt;# The various resources can be given custom developer-friendly names, as shown below.&lt;/span&gt;
  &lt;span class="c1"&gt;# What the resource consists of is determined by the 'type' sub-property found in the files&lt;/span&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="c1"&gt;############################################################&lt;/span&gt;
    &lt;span class="c1"&gt;# DATABASE RESOURCES&lt;/span&gt;
    &lt;span class="c1"&gt;############################################################&lt;/span&gt;
    &lt;span class="c1"&gt;# Data table for this microserver&lt;/span&gt;
    &lt;span class="na"&gt;ResourceTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;${file(./resources/aws/dynamodb/ResourceTable.yml)}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;h4&gt;
  
  
  a) Change our service name
&lt;/h4&gt;

&lt;p&gt;Change the service value from &lt;code&gt;myrestproject&lt;/code&gt; to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.resourceName}Service&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that for this value, we have introduced for the first time the use of a variable value.  These come in the format: &lt;code&gt;${source:key}&lt;/code&gt;.  For references to the present serverless file, the source is &lt;code&gt;self&lt;/code&gt;.  So the value for our &lt;code&gt;service&lt;/code&gt; key is now going to consist of the value located at &lt;code&gt;custom.resourceName&lt;/code&gt; concatenated with 'Service'.  Note that we are referencing a value that has not yet been defined at this point in the file--it is okay if it is defined further down in the file.  So let's get to it.&lt;/p&gt;

&lt;h4&gt;
  
  
  b) 'custom' top level entry
&lt;/h4&gt;

&lt;p&gt;The Serverless Framework defines at top level of our YAML hierarchy a &lt;code&gt;custom&lt;/code&gt; key, which can be used to hold many of our installation-specific values.  The various key-value pairs in this &lt;code&gt;custom&lt;/code&gt; section are user-defined however we see fit.&lt;/p&gt;

&lt;p&gt;We'll go ahead and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#############################################################################################&lt;/span&gt;
&lt;span class="c1"&gt;# CUSTOM VARIABLES - all variables necessary to get up and running should be in this section&lt;/span&gt;
&lt;span class="c1"&gt;#############################################################################################&lt;/span&gt;
&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Name of our REST resource, e.g. 'players', 'team', 'league', etc.&lt;/span&gt;
  &lt;span class="na"&gt;resourceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;teams&lt;/span&gt;
  &lt;span class="c1"&gt;# Email address of primary contact; embedded into internal "Tags" to aid in&lt;/span&gt;
  &lt;span class="c1"&gt;# internal maintenance&lt;/span&gt;
  &lt;span class="na"&gt;primaryContact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;YOUR EMAIL ADDRESS&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;YOUR AWS REGION&amp;gt;&lt;/span&gt;

  &lt;span class="na"&gt;dynamodb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# For tables, I have adopted a naming convention of &amp;lt;SERVICE&amp;gt;-Table-&amp;lt;EntityName&amp;gt;-&amp;lt;Stage&amp;gt;; e.g. SportsApp-Table-Players-dev&lt;/span&gt;
    &lt;span class="na"&gt;resourceTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:service}-Table-${self:custom.resourceName}-${self:provider.stage}&lt;/span&gt;
    &lt;span class="c1"&gt;# For indexes, I have adopted a naming convention of &amp;lt;SERVICE&amp;gt;-TableIdx-&amp;lt;EntityName&amp;gt;-&amp;lt;Constraint/SearchKey&amp;gt;-&amp;lt;Stage&amp;gt;; e.g. SportsApp-TableIdx-Players-LastName-dev&lt;/span&gt;
    &lt;span class="na"&gt;resourceTableIdx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:service}-TableIdx-${self:custom.resourceName}-Name-${self:provider.stage}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this example, we'll create a RESTful API for a 'teams' resource.  (Note the use of plural and lowercase).  This means the service key we defined earlier will be set to 'teamsService'.&lt;/p&gt;

&lt;p&gt;Be sure to put in your email address and your AWS region (e.g. &lt;code&gt;us-east-2&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We have also defined a key-value branch called &lt;code&gt;dynamodb&lt;/code&gt; (again, we could have called it anything, like &lt;code&gt;myNotSqlParameters&lt;/code&gt;) with two child values: (1) the eventual name of our database "table"; and (2) the eventual name of our  "table"'s uniqueness index (we'll explain this later when discussion data storage).&lt;/p&gt;

&lt;p&gt;You'll recall that ${self:service} = &lt;code&gt;teamsService&lt;/code&gt; and ${self:custom.resourceName} = &lt;code&gt;teams&lt;/code&gt; and the default stage is &lt;code&gt;dev&lt;/code&gt; so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resourceTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:service}-Table-${self:custom.resourceName}-${self:provider.stage}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will become&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resourceTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;teamsService-Table-teams-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By including the stage (&lt;code&gt;dev&lt;/code&gt;) in name of all deployed resource such as the table and index names, we ensure our development environment won't interfere with our production (&lt;code&gt;prod&lt;/code&gt;) environment.&lt;/p&gt;

&lt;h4&gt;
  
  
  c) 'provider'
&lt;/h4&gt;

&lt;p&gt;We are now going to add a few more keys to the provider section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs14.x&lt;/span&gt;
  &lt;span class="na"&gt;lambdaHashingVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20201221&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;  
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.region}&lt;/span&gt;

  &lt;span class="na"&gt;apiGateway&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# setting required for the transition from Serverless Framework 2.0 to 3.0+&lt;/span&gt;
    &lt;span class="na"&gt;shouldStartNameWithService&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;


  &lt;span class="c1"&gt;# Environment variables our Javascript code relies on&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:provider.stage}&lt;/span&gt;
    &lt;span class="na"&gt;TABLE_NAME_TEAM&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.dynamodb.resourceTable}&lt;/span&gt;
    &lt;span class="na"&gt;TABLE_IDX_TEAM_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.dynamodb.resourceTableIdx}&lt;/span&gt;

  &lt;span class="c1"&gt;# Base IAm role that the lambdas will execute with&lt;/span&gt;
  &lt;span class="na"&gt;iam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./resources/aws/iam/LambdaRole.yml)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To start, we now explicitly set the stage to &lt;code&gt;dev&lt;/code&gt;,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which you will recall is the default.  We can override this during deployment using command line parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;serverless deploy &lt;span class="nt"&gt;--stage&lt;/span&gt; prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We next introduce for the first time the re-use of our custom parameters from higher in the file by setting &lt;code&gt;region&lt;/code&gt; using the previously defined &lt;code&gt;${self.custom.region}&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.region}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, this lets us keep most of our deployment configuration in one place under &lt;code&gt;custom&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is followed by another Serverless transition variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiGateway&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;shouldStartNameWithService&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting in 3.0, the naming convention in the deployments will change from &lt;code&gt;{stage}-{service}&lt;/code&gt; to &lt;code&gt;{service}-{stage}&lt;/code&gt;.   We should just adopt this approach from the get-go.&lt;/p&gt;

&lt;p&gt;Next we set environment variables that will be passed into the Node.js runtime environment.  This is a means for communicating our configuration to our javascript code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:provider.stage}&lt;/span&gt;
    &lt;span class="na"&gt;TABLE_NAME_TEAM&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.dynamodb.resourceTable}&lt;/span&gt;
    &lt;span class="na"&gt;TABLE_IDX_TEAM_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.dynamodb.resourceTableIdx}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our javascript code will be able to look these up by examining the runtime environment variables.  We pass: (1) the deployment stage; (2) our "table" name; and (3) our "table" uniqueness index name.&lt;/p&gt;

&lt;p&gt;Finally, we add our first IAm configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="c1"&gt;# Base IAm role that the lambdas will execute with&lt;/span&gt;
  &lt;span class="na"&gt;iam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./resources/aws/iam/LambdaRole.yml)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notably, we do this by introducing the file import concept.  Serverless allows us to break individual portions of our base configuration file into discrete files.  Separating our configuration file into subfiles provides a number of benefits, including: (1) more granular version control; (2) smaller more readable files; and (3) a consistent, known location for finding settings in any given module.&lt;/p&gt;

&lt;p&gt;We'll go over the contents of this file in a bit, but first let's stay focused on our &lt;code&gt;serverless.yml&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  d) &lt;code&gt;plugins&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;We are next going to add a new top-level entry called &lt;code&gt;plugins&lt;/code&gt;.  This key contains a &lt;code&gt;yaml&lt;/code&gt; list of Serverless Framework extensions used by our project.  I generally try to keep these to a minimum due to inconsistency in the maintenance frequency of the various plugins.  The two I find absolutely essential are (a) &lt;code&gt;serverless-plugin-typescript&lt;/code&gt;, which provides TypeScript support on top of Javascript; and (b) &lt;code&gt;serverless-offline&lt;/code&gt;, which allows offline development of our lambda modules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Serverless Framework plugins&lt;/span&gt;
&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# support for typescript&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-plugin-typescript&lt;/span&gt;

  &lt;span class="c1"&gt;# Allows us to use a local instance during development, eliminating need&lt;/span&gt;
  &lt;span class="c1"&gt;# to publish to cloud to see changes to functions and allowing use of a debugger&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-offline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  e) &lt;code&gt;functions&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;You'll recall this previously consisted of a structured key-value tree listing the base &lt;code&gt;hello&lt;/code&gt; function.  We are going to replace this with a file import.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# define all of our REST microservice endpoints&lt;/span&gt;
&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./resources/aws/RESTFunctions.yml)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  f) &lt;code&gt;package&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Another new top-level key.  This defines setting relating to the packaging of our stack for deployment.  The only value we will include is &lt;code&gt;excludeDevDependencies&lt;/code&gt;, which will filter out of our deployment modules relating to our precompiler (Typescript) and our testing harness (Jest).  (Note that this value is &lt;code&gt;true&lt;/code&gt; by default, so this value is functionally useless as set.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Settings relating to how our module will be bundled for execution&lt;/span&gt;
&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Don't include node_modules like typescript and unit testing when&lt;/span&gt;
  &lt;span class="c1"&gt;# publishing our bundle to the cloud; results in notably smaller upload bundle&lt;/span&gt;
  &lt;span class="na"&gt;excludeDevDependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  g) &lt;code&gt;resources&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Finally, our last top level key.   Various catch-all resource creation happens here, including the definition of our "table".  (Later on, we are going to define our user authentication here as well but we'll skip this for now).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Values that we want to export out of this service for use in other services&lt;/span&gt;
  &lt;span class="c1"&gt;# Including an export name pollutes the global namespace and is only necessary&lt;/span&gt;
  &lt;span class="c1"&gt;# when you don't know this Stack's name, as you can otherwise obtain the value&lt;/span&gt;
  &lt;span class="c1"&gt;# using the key name you chose below, e.g. 'ApiGatewayRestApiExport'&lt;/span&gt;
  &lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ApiGatewayRestApiExport&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ApiGatewayRestApi'&lt;/span&gt;
&lt;span class="c1"&gt;#      Export:&lt;/span&gt;
&lt;span class="c1"&gt;#        Name: ${self:service}-${self:provider.stage}-api&lt;/span&gt;

  &lt;span class="c1"&gt;# The various resources can be given custom developer-friendly names, as shown below.&lt;/span&gt;
  &lt;span class="c1"&gt;# What the resource consists of is determined by the 'type' sub-property found in the files&lt;/span&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="c1"&gt;############################################################&lt;/span&gt;
    &lt;span class="c1"&gt;# DATABASE RESOURCES&lt;/span&gt;
    &lt;span class="c1"&gt;############################################################&lt;/span&gt;
    &lt;span class="c1"&gt;# Data table for this microserver&lt;/span&gt;
    &lt;span class="na"&gt;ResourceTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;${file(./resources/aws/dynamodb/ResourceTable.yml)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  i) &lt;code&gt;Outputs&lt;/code&gt;
&lt;/h5&gt;

&lt;p&gt;Here we instruct AWS what values should be "exported" from our stack.  This is done in either of two ways: (1) we can make a value available in our AWS global namespace; or (2) we can make a value available as a parameter attached to our stack name.  I personally hate polluting the global namespace and see little value to it, so I take the second approach (but leave an example of the 1st approach commented out in the code).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ApiGatewayRestApiExport&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ApiGatewayRestApi'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we define an export key named &lt;code&gt;ApiGatewayRestApiExport&lt;/code&gt;--this could have been anything we wanted, such as &lt;code&gt;MyDogSpot&lt;/code&gt;.  For the value, we for the first time use the &lt;code&gt;!Ref&lt;/code&gt; command.  The !Ref command instructs AWS to inject the as-deployed unique name of our ApiGatewayRestAPI object.  &lt;/p&gt;

&lt;p&gt;Now, if you've been paying attention, you might be saying right now "WHAT ApiGatewayRestApi object!??"  When deploying our stack, Serverless creates a resource in AWS's system named 'ApiGatewayRestApi' that routes requests to our lambda.  By exporting its value, we will be able to get a handle to it at a future stage.&lt;/p&gt;

&lt;h5&gt;
  
  
  i) &lt;code&gt;Resources&lt;/code&gt;
&lt;/h5&gt;

&lt;p&gt;Somewhat confusingly, the &lt;code&gt;resources&lt;/code&gt; key has a child named &lt;code&gt;Resources&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="c1"&gt;############################################################&lt;/span&gt;
    &lt;span class="c1"&gt;# DATABASE RESOURCES&lt;/span&gt;
    &lt;span class="c1"&gt;############################################################&lt;/span&gt;
    &lt;span class="c1"&gt;# Data table for this microserver&lt;/span&gt;
    &lt;span class="na"&gt;ResourceTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;${file(./resources/aws/dynamodb/ResourceTable.yml)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As noted in the comments, each 'Resources' entry will be of a particular type as indicated by a &lt;code&gt;Type&lt;/code&gt; key with a value such as &lt;code&gt;AWS::DynamoDB::Table&lt;/code&gt;.  These would normally appear here, but because we are using file imports, they will instead be in our sub-files. &lt;/p&gt;

&lt;p&gt;With that, our final &lt;code&gt;serverless.yml&lt;/code&gt; file looks like this for the time being:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app and org for integration with dashboard.serverless.com&lt;/span&gt;
&lt;span class="c1"&gt;# Note that using this will cause Serverless to inject a logging handler proxy&lt;/span&gt;
&lt;span class="c1"&gt;# before the calls to your lambda functions, resulting in the renaming of your handler&lt;/span&gt;
&lt;span class="c1"&gt;# in the AWS interface&lt;/span&gt;
&lt;span class="c1"&gt;#org: &amp;lt;your_org_name_here&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#app: &amp;lt;your_dashboard_appname_here&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;# name of our microservice&lt;/span&gt;
&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.resourceName}Service&lt;/span&gt;

&lt;span class="na"&gt;frameworkVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=2.0'&lt;/span&gt;
&lt;span class="na"&gt;variablesResolutionMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20210219&lt;/span&gt;

&lt;span class="c1"&gt;#############################################################################################&lt;/span&gt;
&lt;span class="c1"&gt;# CUSTOM VARIABLES - all variables necessary to get up and running should be in this section&lt;/span&gt;
&lt;span class="c1"&gt;#############################################################################################&lt;/span&gt;
&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;resourceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;teams&lt;/span&gt;
  &lt;span class="c1"&gt;# Email address of primary contact; embedded into internal "Tags" to aid in&lt;/span&gt;
  &lt;span class="c1"&gt;# internal maintenance&lt;/span&gt;
  &lt;span class="na"&gt;primaryContact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;YOUR EMAIL ADDRESS&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;YOUR AWS REGION&amp;gt;&lt;/span&gt;

  &lt;span class="na"&gt;dynamodb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# For tables, I have adopted a naming convention of &amp;lt;SERVICE&amp;gt;-Table-&amp;lt;EntityName&amp;gt;-&amp;lt;Stage&amp;gt;; e.g. SportsApp-Table-Players-dev&lt;/span&gt;
    &lt;span class="na"&gt;resourceTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:service}-Table-${self:custom.resourceName}-${self:provider.stage}&lt;/span&gt;
    &lt;span class="c1"&gt;# For indexes, I have adopted a naming convention of &amp;lt;SERVICE&amp;gt;-TableIdx-&amp;lt;EntityName&amp;gt;-&amp;lt;Constraint/SearchKey&amp;gt;-&amp;lt;Stage&amp;gt;; e.g. SportsApp-TableIdx-Players-LastName-dev&lt;/span&gt;
    &lt;span class="na"&gt;resourceTableIdx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:service}-TableIdx-${self:custom.resourceName}-Name-${self:provider.stage}&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="c1"&gt;# AWS claims they support NodeJS14, but as of March 2021, certain Node14 features don't appear to function correctly, e.g. nullish coalescing&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs14.x&lt;/span&gt;
  &lt;span class="na"&gt;lambdaHashingVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20201221&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;  
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.region}&lt;/span&gt;

  &lt;span class="na"&gt;apiGateway&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# setting required for the transition from Serverless Framework 2.0 to 3.0+&lt;/span&gt;
    &lt;span class="na"&gt;shouldStartNameWithService&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

    &lt;span class="c1"&gt;# we can have AWS API Gateway validate incoming requests prior to sending it to our lambda,&lt;/span&gt;
    &lt;span class="c1"&gt;# saving us the processing cost for malformed requests&lt;/span&gt;
    &lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;schemas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;resource-create-model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.resourceName}CreateModel&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(src/schema/createResourceSchema.json)}&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Model&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;validation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;creating&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;${self:custom.resourceName}"&lt;/span&gt;

  &lt;span class="c1"&gt;# Environment variables our Javascript code relies on&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:provider.stage}&lt;/span&gt;
    &lt;span class="na"&gt;TABLE_NAME_TEAM&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.dynamodb.resourceTable}&lt;/span&gt;
    &lt;span class="na"&gt;TABLE_IDX_TEAM_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.dynamodb.resourceTableIdx}&lt;/span&gt;

  &lt;span class="c1"&gt;# Base IAm role that the lambdas will execute with&lt;/span&gt;
  &lt;span class="na"&gt;iam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./resources/aws/iam/LambdaRole.yml)}&lt;/span&gt;

&lt;span class="c1"&gt;# Serverless Framework plugins&lt;/span&gt;
&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# support for typescript&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-plugin-typescript&lt;/span&gt;

  &lt;span class="c1"&gt;# Allows us to use a local instance during development, eliminating need&lt;/span&gt;
  &lt;span class="c1"&gt;# to publish to cloud to see changes to functions and allowing use of a debugger&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-offline&lt;/span&gt;

&lt;span class="c1"&gt;# define all of our REST microservice endpoints&lt;/span&gt;
&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./resources/aws/RESTFunctions.yml)}&lt;/span&gt;

&lt;span class="c1"&gt;# Settings relating to how our module will be bundled for execution&lt;/span&gt;
&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Don't include node_modules like typescript and unit testing when&lt;/span&gt;
  &lt;span class="c1"&gt;# publishing our bundle to the cloud; results in notably smaller upload bundle&lt;/span&gt;
  &lt;span class="na"&gt;excludeDevDependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Values that we want to export out of this service for use in other services&lt;/span&gt;
  &lt;span class="c1"&gt;# Including an export name pollutes the global namespace and is only necessary&lt;/span&gt;
  &lt;span class="c1"&gt;# when you don't know this Stack's name, as you can otherwise obtain the value&lt;/span&gt;
  &lt;span class="c1"&gt;# using the key name you chose below, e.g. 'ApiGatewayRestApiExport'&lt;/span&gt;
  &lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ApiGatewayRestApiExport&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ApiGatewayRestApi'&lt;/span&gt;
&lt;span class="c1"&gt;#      Export:&lt;/span&gt;
&lt;span class="c1"&gt;#        Name: ${self:service}-${self:provider.stage}-api&lt;/span&gt;

  &lt;span class="c1"&gt;# The various resources can be given custom developer-friendly names, as shown below.&lt;/span&gt;
  &lt;span class="c1"&gt;# What the resource consists of is determined by the 'type' sub-property found in the files&lt;/span&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="c1"&gt;############################################################&lt;/span&gt;
    &lt;span class="c1"&gt;# DATABASE RESOURCES&lt;/span&gt;
    &lt;span class="c1"&gt;############################################################&lt;/span&gt;
    &lt;span class="c1"&gt;# Data table for this microserver&lt;/span&gt;
    &lt;span class="na"&gt;ResourceTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;${file(./resources/aws/dynamodb/ResourceTable.yml)}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we go on to define the subfiles of our configuration, let's first talk about some of the other file types we will be dealing with.&lt;/p&gt;

&lt;h2&gt;
  
  
  B. Dependencies / &lt;code&gt;Package.json&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;As discussed in the previous post, &lt;code&gt;npm&lt;/code&gt; uses a JSON-based &lt;code&gt;package.json&lt;/code&gt; manifest file to track information about our project dependencies.  This file will be located in our root directory.  The key parts are as follows:&lt;/p&gt;

&lt;h3&gt;
  
  
  1) &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;These are self-explanatory, being (a) the name of our application; (b) a version identifier; and (c) a textual description.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) &lt;code&gt;main&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The primary entry point of our module.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) &lt;code&gt;scripts&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Now things begin to get interesting.  &lt;code&gt;scripts&lt;/code&gt; provides us a way to define a list of commands that we can run using the command &lt;code&gt;npm run &amp;lt;command&amp;gt;&lt;/code&gt;.  For example, &lt;code&gt;npm run coverage&lt;/code&gt; or &lt;code&gt;npm run deploy&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4) &lt;code&gt;devDependencies&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A list of dependencies that are necessary during the compilation and testing phases of development, such as modules to support Typescript, Serverless Framework offline testing, and unit tests.&lt;/p&gt;

&lt;p&gt;Although we can add modules to this list by hand, the normal method is through the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; &amp;lt;module&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the use of the flag &lt;code&gt;--save-dev&lt;/code&gt;.  This tells NPM that the module is a development dependency, rather than a runtime deployment dependency.  If you forget to use the flag, just go ahead and run the command again with the flag and NPM will move the module to the appropriate part of the configuration file.&lt;/p&gt;

&lt;p&gt;NPM will install each of these modules in the "node_modules" subdirectory of our project.&lt;/p&gt;

&lt;p&gt;I use the following as a baseline:&lt;/p&gt;

&lt;h4&gt;
  
  
  a) Serverless modules
&lt;/h4&gt;

&lt;p&gt;The following adds Serverless Framework support, offline Serverless Framework testing and debugging, and Serverless Framework Typescript support.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; serverless
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; serverless-offline
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; serverless-plugin-typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  b) Typescript modules
&lt;/h4&gt;

&lt;p&gt;The first of the following adds Typescript support.  The rest provide Typescript "definitions" for various Javascript modules that do not necessarily have Typescript-support built into them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; typescript
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @types/aws-lambda
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @types/jest
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @types/node
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @types/uuid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  c) Jest Unit Testing modules
&lt;/h4&gt;

&lt;p&gt;The first includes Jest as our unit tester.  The second adds dynamodb support to Jest.  The rest allow Jest to use the "babel" javascript compiler, along with babel support for environment variables and typescript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @shelf/jest-dynamodb

&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; babel-jest
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @babel/core
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @babel/preset-env
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @babel/preset-typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5) &lt;code&gt;dependencies&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A list of dependencies required by our module at runtime.  We ideally want to keep this list small.  We add items to this list by running the &lt;code&gt;npm i&lt;/code&gt; command without the &lt;code&gt;--save-dev&lt;/code&gt; flag. e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i dynamoose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I include only dynamoose (a framework for interacting with DynamoDB) and uuid (a library for generating unique identifiers).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i dynamoose
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i uuid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6) Final package.json file
&lt;/h3&gt;

&lt;p&gt;Our package.json file ends up looking like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"teamMicroservice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is the Team Microservice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tslint -p tsconfig.json -c tslint.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"local"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"serverless offline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"serverless deploy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"coverage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest --coverage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"clean"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"git clean -fXd -e &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;!node_modules -e &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;!node_modules/**/*"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@babel/core"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.13.10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@babel/preset-env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.13.12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@babel/preset-typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.13.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@shelf/jest-dynamodb"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"github:shelfio/jest-dynamodb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/aws-lambda"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.10.51"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^26.0.21"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^14.0.23"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/uuid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.3.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"babel-jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^26.6.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^26.6.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"serverless"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.30.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"serverless-offline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.8.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"serverless-plugin-typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.1.9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.8.3"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dynamoose"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.7.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.3.2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  C. &lt;code&gt;launch.json&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;We'll next briefly touch on this file, which does not yet exist.  The &lt;code&gt;launch.json&lt;/code&gt; file is used to configure the Visual Studio Code debugger.  Later on, we will define multiple debug configurations, including ones to launch (1) Serverless offline in the debugger; (2) all of our Jest unit tests; and (3) debugging our current Jest file.  For now, just know that it will exist and we will customize it when we get into our debugger configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  D. jest.config.js
&lt;/h3&gt;

&lt;p&gt;Jest is our unit test harness.  This file will contain its configuration settings.  To create it, we run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;jest &lt;span class="nt"&gt;--init&lt;/span&gt;
The following questions will &lt;span class="nb"&gt;help &lt;/span&gt;Jest to create a suitable configuration &lt;span class="k"&gt;for &lt;/span&gt;your project

? Would you like to use Jest when running &lt;span class="s2"&gt;"test"&lt;/span&gt; script &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"package.json"&lt;/span&gt;? › &lt;span class="o"&gt;(&lt;/span&gt;Y/n&lt;span class="o"&gt;)&lt;/span&gt; Y
? Would you like to use Typescript &lt;span class="k"&gt;for &lt;/span&gt;the configuration file? › &lt;span class="o"&gt;(&lt;/span&gt;y/N&lt;span class="o"&gt;)&lt;/span&gt; N
? Choose the &lt;span class="nb"&gt;test &lt;/span&gt;environment that will be used &lt;span class="k"&gt;for &lt;/span&gt;testing › - Use arrow-keys. Return to submit.
❯   node
    jsdom &lt;span class="o"&gt;(&lt;/span&gt;browser-like&lt;span class="o"&gt;)&lt;/span&gt;
? Do you want Jest to add coverage reports? &lt;span class="o"&gt;(&lt;/span&gt;y/N&lt;span class="o"&gt;)&lt;/span&gt; N
? Which provider should be used to instrument code &lt;span class="k"&gt;for &lt;/span&gt;coverage? › - Use arrow-keys. Return to submit.
❯   v8
    babel
? Automatically clear mock calls and instances between every &lt;span class="nb"&gt;test&lt;/span&gt;? › &lt;span class="o"&gt;(&lt;/span&gt;y/N&lt;span class="o"&gt;)&lt;/span&gt; Y
  Modified &amp;lt;MYPATH&amp;gt;/MyRESTProject/package.json

  Configuration file created at &amp;lt;MYPATH&amp;gt;/MyRESTProject/jest.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll configure it further later to add DynamoDB support.  For now, let's move on.&lt;/p&gt;

&lt;h1&gt;
  
  
  II. Our Directory Structure
&lt;/h1&gt;

&lt;p&gt;Like those of you coming from a Spring Maven world, I generally prefer a project hierarchy consisting of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;|____src
| |____main
| | |____resources
| | | | &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
| | |____java
| | | | &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
| |____test
| | | &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
|____target
| | &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although we will try to keep the source/resource directory distinction, we will be leaving behind the distinct test tree.  The reason behind this is that with a very concise microservice, we will be placing the unit test for each file in the same directory as the source.  Later on, we will introduce a separate &lt;code&gt;test&lt;/code&gt; tree that will contain only our integration tests.&lt;/p&gt;

&lt;p&gt;Our new directory structure will be akin to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
|____resources
| |____aws
| | |____dynamodb
| | | |____ResourceTable.yml
| | |____RESTFunctions.yml
| | |____iam
| | | |____LambdaRole.yml
|____src
| |____utils
| | |____Response.ts
| | |____rest
| | | |____responses
| | | | |____ &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
| | | |____exceptions
| | | | |____ &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
| |____schema
| | |____ &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
| |____model
| | |____Team.unit.test.ts
| | |____Team.ts
| |____aws
| | |____AWSRestController.ts
| | |____AWSTeamController.ts
| | |____AWSTeamController.unit.test.ts
| |____service
| | |____TeamService.unit.test.ts
| | |____TeamService.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A. &lt;code&gt;src&lt;/code&gt; Folder
&lt;/h2&gt;

&lt;p&gt;We will store our various typescript files in a &lt;code&gt;src&lt;/code&gt; folder.  I'm still somewhat wed to the model/view/controller structure, which influences my tree selection.  From our base project folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; src/aws/
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; src/model/
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; src/schema/
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; src/service/
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; src/utils/rest/responses
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; src/utils/rest/exceptions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll discuss our various source files and their contents in the next post.  For now, let's finish our initial resources files.&lt;/p&gt;

&lt;h2&gt;
  
  
  B. &lt;code&gt;resources&lt;/code&gt; Folder
&lt;/h2&gt;

&lt;p&gt;We will be storing our various &lt;code&gt;serverless.yml&lt;/code&gt; configuration files in a &lt;code&gt;resources&lt;/code&gt; folder.  Under this folder, we'll be creating subfolders for our various AWS components.  From our base project folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; resources/aws/dynamodb
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; resources/aws/iam
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. &lt;code&gt;ResourceTable.yml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;You'll recall that in our &lt;code&gt;serverless.yml&lt;/code&gt; file, we declared our DynamoDB resource as being defined in the file &lt;code&gt;resources/aws/dynamodb/ResourceTable.yml&lt;/code&gt;.  Let's go ahead and create this file and set its contents as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::DynamoDB::Table&lt;/span&gt;
&lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.dynamodb.resourceTable}&lt;/span&gt;
  &lt;span class="na"&gt;ProvisionedThroughput&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ReadCapacityUnits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;WriteCapacityUnits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;AttributeDefinitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
      &lt;span class="na"&gt;AttributeType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;name&lt;/span&gt;
      &lt;span class="na"&gt;AttributeType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sortField&lt;/span&gt;
      &lt;span class="na"&gt;AttributeType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S&lt;/span&gt;
  &lt;span class="na"&gt;KeySchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
      &lt;span class="na"&gt;KeyType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HASH&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sortField&lt;/span&gt;
      &lt;span class="na"&gt;KeyType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RANGE&lt;/span&gt;       
  &lt;span class="na"&gt;LocalSecondaryIndexes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;IndexName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.dynamodb.resourceTableIdx}&lt;/span&gt;
      &lt;span class="na"&gt;KeySchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
            &lt;span class="na"&gt;KeyType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HASH&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;name&lt;/span&gt;
            &lt;span class="na"&gt;KeyType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RANGE&lt;/span&gt;
      &lt;span class="na"&gt;Projection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ProjectionType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;KEYS_ONLY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll go into detail on this later.  &lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;code&gt;LambdaRole.yml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Next, we create our &lt;code&gt;resources/aws/iam/LambdaRole.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This is the permissions that our lambda functions need&lt;/span&gt;
&lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# grant access to dynamoDB table and associated table index&lt;/span&gt;
  &lt;span class="na"&gt;statements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
      &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb:Query"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb:PutItem"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb:Scan"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb:DeleteItem"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb:UpdateItem"&lt;/span&gt;
      &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;ResourceTable.Arn&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s"&gt;arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${self:custom.dynamodb.resourceTable}/index/*&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. &lt;code&gt;RestFunctions.yml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Followed by our &lt;code&gt;resources/aws/RestFunctions.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# For example purposes, finding all entities is an unrestricted operation open to the entire world&lt;/span&gt;
&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./src/aws/AWSTeamController.findAll&lt;/span&gt; 
  &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/${self:custom.resourceName}&lt;/span&gt;  
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt; 
        &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="c1"&gt;# solely for creating a pretty label; sets OperationName in ApiGateway, useful for e.g. Swagger API documentation          &lt;/span&gt;
        &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;getTeams&lt;/span&gt; 

&lt;span class="c1"&gt;# For example purposes, looking up the details on a single entity requires obtaining authorization from IAM&lt;/span&gt;
&lt;span class="na"&gt;findOne&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./src/aws/AWSTeamController.findOne&lt;/span&gt;
  &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/${self:custom.resourceName}/{id}&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
        &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="c1"&gt;# authorization provided by IAm, rather than a custom authorizer or the COGNITO user pool&lt;/span&gt;
        &lt;span class="c1"&gt;# even though there is a Cognito UserPool at the bottom of this all&lt;/span&gt;
        &lt;span class="c1"&gt;# this AWS_IAM approach allows the restrictions to be based on a IAm Policy&lt;/span&gt;
        &lt;span class="c1"&gt;# and we previously handed out policies through our Cognito Identity Pool based on a user's&lt;/span&gt;
        &lt;span class="c1"&gt;# highest priority UserPool group; This also avoids a lambda execution in order to run a custom authorizer&lt;/span&gt;
        &lt;span class="c1"&gt;# authorizer:&lt;/span&gt;
        &lt;span class="c1"&gt;#  type: AWS_IAM   &lt;/span&gt;

&lt;span class="c1"&gt;# Generally, deleting items should always require authorization&lt;/span&gt;
&lt;span class="na"&gt;deleteOne&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./src/aws/AWSTeamController.deleteOne&lt;/span&gt;
  &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/${self:custom.resourceName}/{id}&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;delete&lt;/span&gt;
        &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="c1"&gt;# Again we use a AWS_IAM authorizer and not a Cognito User Pool or custom authorizer&lt;/span&gt;
        &lt;span class="c1"&gt;#authorizer:&lt;/span&gt;
        &lt;span class="c1"&gt;#  type: AWS_IAM&lt;/span&gt;

&lt;span class="c1"&gt;# Generally, updating items should always require authorization&lt;/span&gt;
&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./src/aws/AWSTeamController.update&lt;/span&gt;
  &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/${self:custom.resourceName}/{id}&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;put&lt;/span&gt;
        &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="c1"&gt;#authorizer:&lt;/span&gt;
        &lt;span class="c1"&gt;#  type: AWS_IAM&lt;/span&gt;
        &lt;span class="c1"&gt;# Listing a schema here will have AWS validate the request prior to calling our &lt;/span&gt;
        &lt;span class="c1"&gt;# lambda, saving us execution costs for invalid requests; note that the schema for this&lt;/span&gt;
        &lt;span class="c1"&gt;# extremely simplistic model is the same as for creates, so we re-use the create request schema        &lt;/span&gt;
        &lt;span class="c1"&gt;#request:&lt;/span&gt;
        &lt;span class="c1"&gt;#  schemas:&lt;/span&gt;
        &lt;span class="c1"&gt;#    application/json: resource-create-model&lt;/span&gt;

&lt;span class="c1"&gt;# Generally, creating items should always require authorization&lt;/span&gt;
&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./src/aws/AWSTeamController.create&lt;/span&gt;
  &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/${self:custom.resourceName}&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;post&lt;/span&gt;
        &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="c1"&gt;#authorizer:&lt;/span&gt;
        &lt;span class="c1"&gt;#  type: AWS_IAM&lt;/span&gt;
        &lt;span class="c1"&gt;# Listing a schema here will have AWS validate the request prior to calling our &lt;/span&gt;
        &lt;span class="c1"&gt;# lambda, saving us execution costs for invalid requests        &lt;/span&gt;
        &lt;span class="c1"&gt;#request:&lt;/span&gt;
        &lt;span class="c1"&gt;#  schemas:&lt;/span&gt;
        &lt;span class="c1"&gt;#    application/json: resource-create-model&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we currently have our authorizers disabled, as well as our schema validators.  We'll cover those plus the other various parameters listed above later.  For now, its time to wrap up this post before it gets any longer!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>rest</category>
      <category>cognito</category>
    </item>
    <item>
      <title>Amazon Web Services Sign-Up &amp; Configuration -  Part 4 of Implementing a RESTful API on AWS</title>
      <dc:creator>Chris Straw</dc:creator>
      <pubDate>Sun, 25 Apr 2021 11:55:44 +0000</pubDate>
      <link>https://dev.to/cstraw/amazon-web-services-sign-up-configuration-part-4-of-implementing-a-restful-api-on-aws-4f1d</link>
      <guid>https://dev.to/cstraw/amazon-web-services-sign-up-configuration-part-4-of-implementing-a-restful-api-on-aws-4f1d</guid>
      <description>&lt;p&gt;Quick recap: this is a soup to nuts series covering implementing a full-featured REST API on AWS from the perspective of a long-time infrastructure engineer with a historical preference for Java-based solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1) Create your AWS account
&lt;/h3&gt;

&lt;p&gt;Although some of the Serverless Framework videos are outdated, their AWS Account setup video provides a concise summary of how to sign up for a AWS account. &lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/3rcwUa_H9Ok"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;After that, however, we are going to ignore the Serverless Framework videos and suggestions regarding granting Serverless access to our AWS account. &lt;/p&gt;

&lt;h3&gt;
  
  
  2) Create Administrative user and group
&lt;/h3&gt;

&lt;p&gt;You should now have an AWS account with a single 'root' user.  &lt;/p&gt;

&lt;p&gt;Amazon recommends that, as with OS best practices, you don't use the root account for everyday use, but instead create a separate Administrative user and group.  You'll be using these credentials for your scripted CLI interaction with AWS.  So unless you blindly trust every last random NPM module on the Internet, you'll probably want to go ahead and create these according to Amazon's instructions:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/getting-started_create-admin-group.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/IAM/latest/UserGuide/getting-started_create-admin-group.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll be (1) activating IAm access, (2) creating a user, and (3) creating an Administrator group.  Note that the website lists two ways to do this; you only need to follow the console steps version.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Install Amazon's CLI
&lt;/h3&gt;

&lt;p&gt;Once this is done, the next step is installing the Amazon Command Line Interface (CLI).  &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html" rel="noopener noreferrer"&gt;Instructions can be found here&lt;/a&gt;.   We'll install the newest version, which as of April 2021 is version 2 at:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://awscli.amazonaws.com/AWSCLIV2.pkg" rel="noopener noreferrer"&gt;https://awscli.amazonaws.com/AWSCLIV2.pkg&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; the non-sudo "Install for me only" option defaults to an invalid installation location of "/usr/local" -- a directory that requires &lt;code&gt;root&lt;/code&gt; permission (unlike /usr/local/bin) and therefore causes the installation to fail.  So either fix this by changing the default location (e.g. to ~/Applications) and creating symlinks as described in the instructions (e.g. &lt;code&gt;ln -s ~/Applications/aws-cli/aws /usr/local/bin/aws&lt;/code&gt; and &lt;code&gt;ln -s ~/Applications/aws-cli/aws_completer /usr/local/bin/aws_completer&lt;/code&gt;) or install for all users on the computer if you have &lt;code&gt;root&lt;/code&gt; access.&lt;/p&gt;

&lt;p&gt;Once this is done, go ahead and verify installation of the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;which aws
/usr/local/bin/aws 
&lt;span class="nv"&gt;$ &lt;/span&gt;aws &lt;span class="nt"&gt;--version&lt;/span&gt;
aws-cli/2.1.25 Python/3.7.4 Darwin/20.3.0 exe/x86_64 prompt/off
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4) Provide Your AWS Credentials to AWS CLI
&lt;/h3&gt;

&lt;p&gt;With the CLI installed, we now need to provide it our credentials so that it can interact with AWS services.  Basically, each IAM user account has cryptographic keys that are used to authenticate every request to AWS.  Amazon has an explanation here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are going to run &lt;code&gt;aws configure&lt;/code&gt; and provide our keys, which can be found by going to AWS's IAm user list page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://console.aws.amazon.com/iam/home#/users" rel="noopener noreferrer"&gt;https://console.aws.amazon.com/iam/home#/users&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;then clicking our Administrator, &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjp56fuwmkvi8h69r24y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjp56fuwmkvi8h69r24y.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
then selecting the "Security credentials"&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F382tevpaf6i5vx0wskxx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F382tevpaf6i5vx0wskxx.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Scroll down and select "Create Access Key." &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zs1sfz3m95inczdz7ye.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zs1sfz3m95inczdz7ye.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
 This will create an (1) access key; and (2) secret key; pair.&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz22enjxwyerh4k778wvk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz22enjxwyerh4k778wvk.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;em&gt;Note the various security warnings about keeping this information secret.&lt;/em&gt; (I immediately deleted this pair after creating it for this example.). Also note that you need to either copy/paste both somewhere or download the csv and store it in a safe place, as the secret key is unrecoverable.&lt;/p&gt;

&lt;p&gt;Now, switch back to &lt;code&gt;terminal&lt;/code&gt;, run &lt;code&gt;aws configure&lt;/code&gt;, and provide our credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws configure
AWS Access Key ID &lt;span class="o"&gt;[&lt;/span&gt;None]: &amp;lt;Our access key &lt;span class="nb"&gt;id&lt;/span&gt;, e.g. AKIA....&amp;gt;
AWS Secrete Access Key &lt;span class="o"&gt;[&lt;/span&gt;None]: &amp;lt;Our secret access key&amp;gt;
Default region name &lt;span class="o"&gt;[&lt;/span&gt;None]: &amp;lt;your region, e.g. &lt;span class="s1"&gt;'us-east-2'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
Default output format &lt;span class="o"&gt;[&lt;/span&gt;None]: &amp;lt;just hit enter, default is json&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AWS CLI will now have created two files storing this information: (1) &lt;code&gt;~/.aws/config&lt;/code&gt; and (2) &lt;code&gt;~/.aws/credentials&lt;/code&gt;.  You should now be able to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws iam list-users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and receive a list of the AWS IAm users you have created (in this case, just 'Administrator').&lt;/p&gt;

&lt;h3&gt;
  
  
  5) Create our Empty Serverless Framework Project
&lt;/h3&gt;

&lt;p&gt;We are almost done.  Our last step is to create our skeleton Serverless Framework project.  Make sure you are in whatever directory you keep your workspaces (e.g. &lt;code&gt;~/workspace/&lt;/code&gt;). Go ahead and run &lt;code&gt;serverless&lt;/code&gt;.  We will (1) create a new project; (2) of type 'AWS Node.js'; and (3) called 'MyRESTProject'.  I personally (1) don't enable autoupdate of the Serverless Framework; and (2) turn on command line completion.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;serverless
Serverless: No project detected. Do you want to create a new one? &lt;span class="o"&gt;(&lt;/span&gt;Y/n&lt;span class="o"&gt;)&lt;/span&gt; Y
Serverless: What &lt;span class="k"&gt;do &lt;/span&gt;you want to make? &lt;span class="o"&gt;(&lt;/span&gt;Use arrow keys&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; AWS Node.js
  AWS Python
  Other
Serverless: What &lt;span class="k"&gt;do &lt;/span&gt;you want to call this project? MyRESTProject

Project successfully created &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s1"&gt;'MyRESTProject'&lt;/span&gt; folder.

Serverless: Would you like the Framework to update automatically? &lt;span class="o"&gt;(&lt;/span&gt;Y/n&lt;span class="o"&gt;)&lt;/span&gt; n

Serverless: Would you like to setup a &lt;span class="nb"&gt;command &lt;/span&gt;line &amp;lt;tab&amp;gt; completion? &lt;span class="o"&gt;(&lt;/span&gt;Y/n&lt;span class="o"&gt;)&lt;/span&gt; Y

Serverless: Which Shell &lt;span class="k"&gt;do &lt;/span&gt;you use? &lt;span class="o"&gt;(&lt;/span&gt;use arrow keys&lt;span class="o"&gt;)&lt;/span&gt;
  bash
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; zsh
  fish
Serverless: We will &lt;span class="nb"&gt;install &lt;/span&gt;completion to ~/.zshrc, is it okay ? &lt;span class="o"&gt;(&lt;/span&gt;Y/n&lt;span class="o"&gt;)&lt;/span&gt; Y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now go into our project folder and see we have an empty skeleton:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;MyRESTProject
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;handler.js    serverless.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's verify everything is working by deploying our empty skeleton to AWS using the &lt;code&gt;serverless deploy&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service myrestproject.zip file to S3 &lt;span class="o"&gt;(&lt;/span&gt;392 B&lt;span class="o"&gt;)&lt;/span&gt;...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...............
Serverless: Stack update finished...
Service Information
service: myrestproject
stage: dev
region: us-east-1
stack: myrestproject-dev
resources: 6
api keys:
  None
endpoints:
  None
functions:
  hello: myrestproject-dev-hello
layers:
  None
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can further verify the deployment using AWS's CLI (be sure to specify the right region as listed in your output above):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;aws cloudformation list-stacks &lt;span class="nt"&gt;--stack-status-filter&lt;/span&gt; UPDATE_COMPLETE &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1     
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"StackSummaries"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"StackId"&lt;/span&gt;: &lt;span class="s2"&gt;"arn:aws:cloudformation:us-east-1:--------:stack/myrestproject-dev/----------------"&lt;/span&gt;,
            &lt;span class="s2"&gt;"StackName"&lt;/span&gt;: &lt;span class="s2"&gt;"myrestproject-dev"&lt;/span&gt;,
            &lt;span class="s2"&gt;"TemplateDescription"&lt;/span&gt;: &lt;span class="s2"&gt;"The AWS CloudFormation template for this Serverless application"&lt;/span&gt;,
            &lt;span class="s2"&gt;"CreationTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-04-25T14:38:32.549000+00:00"&lt;/span&gt;,
            &lt;span class="s2"&gt;"LastUpdatedTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-04-25T14:39:07.745000+00:00"&lt;/span&gt;,
            &lt;span class="s2"&gt;"StackStatus"&lt;/span&gt;: &lt;span class="s2"&gt;"UPDATE_COMPLETE"&lt;/span&gt;,
            &lt;span class="s2"&gt;"DriftInformation"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"StackDriftStatus"&lt;/span&gt;: &lt;span class="s2"&gt;"NOT_CHECKED"&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will go ahead and undeploy the test from AWS using &lt;code&gt;serverless remove&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;serverless remove
Serverless: Getting all objects &lt;span class="k"&gt;in &lt;/span&gt;S3 bucket...
Serverless: Removing objects &lt;span class="k"&gt;in &lt;/span&gt;S3 bucket...
Serverless: Removing Stack...
Serverless: Checking Stack delete progress...
..........
Serverless: Stack delete finished...

Serverless: Stack delete finished...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can verify it uninstalled&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws cloudformation list-stacks &lt;span class="nt"&gt;--stack-status-filter&lt;/span&gt; DELETE_COMPLETE &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="s2"&gt;"StackSummaries"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"StackId"&lt;/span&gt;: &lt;span class="s2"&gt;"arn:aws:cloudformation:us-east-1:---------:stack/myrestproject-dev/---------"&lt;/span&gt;,
            &lt;span class="s2"&gt;"StackName"&lt;/span&gt;: &lt;span class="s2"&gt;"myrestproject-dev"&lt;/span&gt;,
            &lt;span class="s2"&gt;"TemplateDescription"&lt;/span&gt;: &lt;span class="s2"&gt;"The AWS CloudFormation template for this Serverless application"&lt;/span&gt;,
            &lt;span class="s2"&gt;"CreationTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-04-25T14:38:32.549000+00:00"&lt;/span&gt;,
            &lt;span class="s2"&gt;"LastUpdatedTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-04-25T14:39:07.745000+00:00"&lt;/span&gt;,
            &lt;span class="s2"&gt;"DeletionTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-04-25T14:43:25.069000+00:00"&lt;/span&gt;,
            &lt;span class="s2"&gt;"StackStatus"&lt;/span&gt;: &lt;span class="s2"&gt;"DELETE_COMPLETE"&lt;/span&gt;,
            &lt;span class="s2"&gt;"DriftInformation"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"StackDriftStatus"&lt;/span&gt;: &lt;span class="s2"&gt;"NOT_CHECKED"&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next time, we'll go about explaining these files and then altering our directory structure to make it more useable.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>rest</category>
      <category>cognito</category>
    </item>
    <item>
      <title>Tool installation and initial configuration - Part 3 of Implementing a RESTful API on AWS</title>
      <dc:creator>Chris Straw</dc:creator>
      <pubDate>Tue, 20 Apr 2021 18:36:15 +0000</pubDate>
      <link>https://dev.to/cstraw/tool-installation-and-initial-configuration-part-3-of-implementing-a-restful-api-on-aws-kl9</link>
      <guid>https://dev.to/cstraw/tool-installation-and-initial-configuration-part-3-of-implementing-a-restful-api-on-aws-kl9</guid>
      <description>&lt;p&gt;Quick recap: this is a soup to nuts series covering implementing a full-featured REST API on AWS from the perspective of a long-time infrastructure engineer with a historical preference for Java-based solutions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Table of contents
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;
Preliminaries - Unavoidable Drawbacks

&lt;ol&gt;
&lt;li&gt;Dependency Creep&lt;/li&gt;
&lt;li&gt;Disparate Licensing Terms&lt;/li&gt;
&lt;li&gt;Goodbye Non-corporate Open-Source, Freeware Build Tools&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;
Tool Installation

&lt;ol&gt;
&lt;li&gt;Node.js - Runtime Engine&lt;/li&gt;
&lt;li&gt;NPM - Build Automation + Package Manager&lt;/li&gt;
&lt;li&gt;VSCode - (Sorta) Integrated Development Environment&lt;/li&gt;
&lt;li&gt;Serverless Framework - Vendor-Agnostic Cloud CLI&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Preliminaries - Unavoidable Drawbacks
&lt;/h2&gt;

&lt;p&gt;I come from a Eclipse/Maven/Apache-based world of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;structured development tools;&lt;/li&gt;
&lt;li&gt;version control;&lt;/li&gt;
&lt;li&gt;debuggers; and&lt;/li&gt;
&lt;li&gt;distrust of libraries that pull in dependencies from all over the Internet.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In moving to a Javascript-based solution, we're going to have to accept a number of compromises on these fronts.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Dependency Creep
&lt;/h3&gt;

&lt;p&gt;For example, when it comes to dependencies, Javascript packages have a tendency to create cascading dependency creep, raising the question of: do I REALLY trust not only the library I am incorporating into my code, but also the cascading libraries that it relies on? Moreover, what license terms have been tacked onto any of these various libraries?  &lt;/p&gt;

&lt;p&gt;This has always been one of the benefits of Java-based development and the various standards-based libraries.  I could have some naive-yet-reasonable expectation that anything bundled by Apache/Sun/Oracle/BEA/RedHat/Spring would be covered by specific licensing terms (let's ignore everything after Java 1.8/8) and wouldn't include some chunk of malware pulled in by a random home-brewed regex library.  &lt;/p&gt;

&lt;p&gt;Unfortunately, we are about to move into a world where incorporating 4-5 libraries results in 150+ random sub-projects being introduced into your code.&lt;/p&gt;

&lt;p&gt;For example, one of the major Javascript testing frameworks--Jest--lists 3 runtime library dependencies.  These then rely on a number of random dependencies, which rely on more random dependencies, etc., etc., until you find yourself including a package called "path-exists"--which I am sure is a wonderful library, but nevertheless is just one more of the 800+ modules that are eventually pulled into my codebase by my handful of initial dependencies.&lt;/p&gt;

&lt;p&gt;There &lt;a href="https://docs.npmjs.com/cli/v7/commands/npm-audit"&gt;are tools out there to help deal with this&lt;/a&gt;, but a new developer should be aware that this is going to be one of the drawbacks of this stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Disparate Licensing Terms
&lt;/h3&gt;

&lt;p&gt;Aside from the security implications, each of these is a library you will eventually need to check from a licensing standpoint.  Although &lt;a href="https://dev.to/connorbode/checking-the-licenses-used-by-your-npm-dependencies-58bi"&gt;there are yet again tools to aide you in this task&lt;/a&gt;, it can be time-consuming (albeit nowhere near as time-consuming as writing your own code in place of these libraries).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Goodbye Non-corporate Open-Source, Freeware Build Tools
&lt;/h3&gt;

&lt;p&gt;Finally, one last point before moving onto setting up our build environment: we're leaving behind the open-source build environment of the 1980s-2000s and entering the world of corporate-controlled open-source.&lt;/p&gt;

&lt;p&gt;For example, the two primary package managers used with Javascript modules are &lt;a href="https://www.npmjs.com"&gt;npm&lt;/a&gt; and &lt;a href="https://yarnpkg.com"&gt;yarn&lt;/a&gt;.  Although both of these products walk and talk like Apache's &lt;a href="http://maven.apache.org"&gt;Maven&lt;/a&gt;, NPM is part of &lt;a href="https://www.npmjs.com/about"&gt;Microsoft's Github subsidiary&lt;/a&gt;, while Yarn (like Jest) originates with &lt;a href="https://engineering.fb.com/2016/10/11/web/yarn-a-new-package-manager-for-javascript/"&gt;Facebook&lt;/a&gt;.  Likewise, when it comes to IDEs, chances are you are going to be using &lt;a href="https://visualstudio.microsoft.com"&gt;Microsoft Visual Studio&lt;/a&gt;--goodbye &lt;a href="https://www.eclipse.org"&gt;Eclipse Software Foundation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Obviously, being corporate projects doesn't necessarily make them bad (see &lt;a href="https://www.wildfly.org/about/"&gt;Redhat's Wildfly&lt;/a&gt;), but those of us who have been disappointed with the evolution of Java after Oracle's acquisition of Sun should be forgiven for wanting to see their build tools originate from an entity like Apache.&lt;/p&gt;

&lt;p&gt;Fortunately, &lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt; itself--our back-end runtime environment--is part of the &lt;a href="https://openjsf.org/projects/"&gt;OpenJS Foundation&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Tool Installation
&lt;/h2&gt;

&lt;p&gt;All of the following instructions assume you are running MacOS.  Also, although I prefer installing most everything inside of a Docker image for security and consistency, we are going to skip that as it adds too much complexity for this tutorial.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Node.js - Runtime Engine
&lt;/h3&gt;

&lt;p&gt;First, we'll need to install Node.js.  Node.js is the back-end runtime engine for our Javascript code, somewhat like the actual &lt;code&gt;java&lt;/code&gt; command.  &lt;/p&gt;

&lt;p&gt;Check to see if it is installed.  We want at least version 12, preferably version 14.  In early 2021, AWS claimed it added support for version 14, but as of February 2021, certain features, like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator"&gt;nullish coalescing&lt;/a&gt;, seemed to be broken.  Either way, check to see if it is installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; node &lt;span class="nt"&gt;--version&lt;/span&gt;
v15.2.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; node &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="nt"&gt;-bash&lt;/span&gt;: node: &lt;span class="nb"&gt;command &lt;/span&gt;not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it is available &lt;a href="https://nodejs.org/en/download/"&gt;available here&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;NPM - Build Automation + Package Manager
&lt;/h3&gt;

&lt;p&gt;In the Java world, we relied on build tools like &lt;a href="http://maven.apache.org"&gt;Maven&lt;/a&gt; to handle our builds and package management (or, to really date myself, &lt;a href="https://ant.apache.org"&gt;Ant build.xml files&lt;/a&gt; and &lt;a href="https://www.gnu.org/software/make/"&gt;Make Makefiles&lt;/a&gt;).  &lt;/p&gt;

&lt;p&gt;With Javascript, it is a two horse race between &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt;. For all intents and purposes, they are interchangeable. Because I generally avoid Facebook, we will be using &lt;code&gt;npm&lt;/code&gt; (and yes, I will later hypocritically recommend using &lt;code&gt;jest&lt;/code&gt; over &lt;code&gt;mocha&lt;/code&gt; as a testing framework). Also, &lt;code&gt;npm&lt;/code&gt; is included with Node.js.&lt;/p&gt;

&lt;p&gt;You can verify npm is installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; npm &lt;span class="nt"&gt;--version&lt;/span&gt;
v7.0.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whereas maven uses POM manifest files, &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt; use a JSON-based &lt;code&gt;package.json&lt;/code&gt; manifest file to track information about your dependencies and build.  As should be self-evident from the filename, Javascript tools tend to use JSON (or YAML) instead of the more structured (and verbose) XML.  &lt;/p&gt;

&lt;p&gt;Example package.json file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is my app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tslint -p tsconfig.json -c tslint.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"local"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"serverless offline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"serverless deploy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"coverage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest --coverage"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@babel/core"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.13.10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@babel/preset-env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.13.12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@babel/preset-typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.13.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@shelf/jest-dynamodb"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"github:shelfio/jest-dynamodb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/aws-lambda"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.10.51"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/aws-sdk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.7.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^26.0.21"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^14.0.23"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/uuid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.3.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"babel-jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^26.6.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^26.6.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"serverless"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.30.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"serverless-offline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.8.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"serverless-plugin-typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.1.9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.8.3"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dynamoose"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.7.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.3.2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moreover, because the dependency creep inherent in Javascript modules, &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt; users discovered it can be difficult to ensure the exact versions they are relying on in dependencies of dependencies (&lt;code&gt;package.json&lt;/code&gt; only lists your direct dependencies).  &lt;/p&gt;

&lt;p&gt;To solve this problem, &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt; litter your directory with yet another file: &lt;code&gt;package-lock.json&lt;/code&gt;.  This file endeavors to list the exact version of every dependency in your dependency tree.&lt;/p&gt;

&lt;p&gt;The ~30 line &lt;code&gt;package.json&lt;/code&gt; file listed above results in a 33,000+ line &lt;code&gt;package-lock.json&lt;/code&gt; along the lines of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"node_modules/@babel/core/node_modules/ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"resolved"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"integrity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"node_modules/@babel/core/node_modules/semver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6.3.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"resolved"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"integrity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"bin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"semver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bin/semver.js"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"node_modules/@babel/generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7.13.9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"resolved"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"integrity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw=="&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@babel/types"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.13.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"jsesc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.5.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"source-map"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^0.5.0"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: although both &lt;code&gt;yarn&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt; use &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;package-lock.json&lt;/code&gt;, it generally advisable to stick to one package manager, rather than switching back and forth between the two.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;VS Code - (Sorta) Integrated Development Environment
&lt;/h3&gt;

&lt;p&gt;For all its drawbacks, the &lt;a href="https://www.eclipse.org/projects/"&gt;Eclipse IDE&lt;/a&gt; provides a robust enterprise development environment with a variety of following invaluable features.&lt;br&gt;

  Some features that I find invaluable
  &lt;ul&gt;
&lt;li&gt;code writing with syntax highlighting&lt;/li&gt;
&lt;li&gt;function and method code completion&lt;/li&gt;
&lt;li&gt;easy refactoring of classes, methods, and functions&lt;/li&gt;
&lt;li&gt;synchronization with git version control&lt;/li&gt;
&lt;li&gt;unit testing, coverage, and quality control via integration with, e.g., testng and sonarqube&lt;/li&gt;
&lt;li&gt;robust debugging with tracing and breakpoints&lt;/li&gt;
&lt;li&gt;server management tools for, e.g., Spring Boot, WildFly, JBoss, etc.
&lt;/li&gt;
&lt;/ul&gt;




&lt;/p&gt;
&lt;p&gt;Unfortunately, in our transition to Javascript and AWS-based serverless, we are going to be jettisoning Eclipse and shifting over to a more watered-down development environment: &lt;a href="https://code.visualstudio.com"&gt;Visual Studio Code&lt;/a&gt;.  (Note that there are other options out there, such as &lt;a href="https://www.jetbrains.com/webstorm/"&gt;Webstorm from JetBrains&lt;/a&gt;, but Visual Studio is arguably the most widely used).&lt;/p&gt;

&lt;p&gt;Go ahead and grab a copy from: &lt;a href="https://code.visualstudio.com"&gt;https://code.visualstudio.com&lt;/a&gt;.  After installation, you should have a screen like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3inELB42--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rva9isphougxhgos57k4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3inELB42--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rva9isphougxhgos57k4.png" alt="VS Code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll get into the details later, but one of the first things you'll notice is that the pulldown menus are not as robust as in Eclipse.  Rather, VS Code has gone the way of &lt;code&gt;vi&lt;/code&gt;, with a large toolbox of hotkeys and commands hidden from view.  A list of various keyboard shortcuts can be found off the menu:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CyZfvWBh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2r83dydkrau853ta2hok.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CyZfvWBh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2r83dydkrau853ta2hok.png" alt="VSCode's Keyboard Shortcuts"&gt;&lt;/a&gt;&lt;br&gt;
as well as &lt;a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf"&gt;online&lt;/a&gt;.  The primary keystroke to remember is either FN1 or ↑⌘P to open a command search pulldown that Visual Code calls the "Command Palette" (never mind that this 'palette' is neither a board nor artistic).&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zHYt-rOS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gf31r91nki7coy28kpz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zHYt-rOS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gf31r91nki7coy28kpz4.png" alt="VSCode's So-called Command Palette"&gt;&lt;/a&gt;&lt;br&gt;
For now, we are going to want to install the &lt;code&gt;code&lt;/code&gt; shell command so we can launch VSCode from our working directory in terminal.  So go ahead and type &lt;code&gt;shell&lt;/code&gt; in the "Command Palette" and select it, which will install the command in your path:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--waRrs4kY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tw8dwzv8fzk7kz7njiqy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--waRrs4kY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tw8dwzv8fzk7kz7njiqy.png" alt="Shell Command Installation"&gt;&lt;/a&gt;&lt;br&gt;
In the bottom right corner, you should receive a popup:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QwrBRFQl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8215jxfrk6pp2r87dqfi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QwrBRFQl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8215jxfrk6pp2r87dqfi.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
If you pop open terminal (⌘-Space then &lt;code&gt;terminal&lt;/code&gt;), you should now be able to execute the &lt;code&gt;code&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;One of VSCode's strengths is a robust selection of extensions, which you can access from the 4 "cubes" icon on the left "Activity Bar". I run with the following basic extensions amongst others:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yqcJMlLD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ra0yrod1bzre7egnya6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yqcJMlLD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ra0yrod1bzre7egnya6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
They provide functionality like (a) code cleanup; (b) improved readability; (c) more legible icons in file lists; (d) autocompletion; and (e) code quality checks.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Serverless Framework
&lt;/h3&gt;

&lt;p&gt;Next we need to get the tools necessary to start working with Amazon Web Services.  As I noted earlier, I like a formal development environment that includes (a) version control; (b) automated testing; (c) debuggers; and (d) consistent deployment.  Accordingly, I want my deployments done according to a repeatable script that (1) I can check into my version control system; and (2) can be placed into a debug harness.&lt;/p&gt;

&lt;p&gt;Unfortunately, AWS historically was poorly designed from this standpoint.  Rather than focus on a command-line driven deployment, application configuration is instead web page driven (an issue now somewhat addressed with the &lt;code&gt;aws&lt;/code&gt; CLI).&lt;/p&gt;

&lt;p&gt;Even now, much of its documentation and tutorials have the user step through web page after web page of deployment, with the underlying configurations created by these pages often hidden from view.  Moreover, it generally lacks the offline lambda function debugger functionality one would want in a true enterprise development environment.&lt;/p&gt;

&lt;p&gt;This is where the &lt;a href="https://www.serverless.com/"&gt;Serverless Framework&lt;/a&gt; comes in.  The Serverless Framework provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a level of cloud-server abstraction giving one's code the veneer of avoiding vendor lock-in;&lt;/li&gt;
&lt;li&gt;parameter-based naming and references of resources;&lt;/li&gt;
&lt;li&gt;a robust offline mock server testing environment;&lt;/li&gt;
&lt;li&gt;ability to run attach a debugger to the server; and&lt;/li&gt;
&lt;li&gt;fully scripted deployment of resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Serverless has both an open-source and a commercial product.  We are only going to cover the open-source solution.  Serverless also provides a web-based monitoring dashboard, but we won't be using this for the time being.&lt;/p&gt;

&lt;p&gt;Serverless includes a &lt;a href="https://www.serverless.com/framework/docs/getting-started/"&gt;relatively decent installation instructions&lt;/a&gt; on their website.  Keep in mind, however, that it appears to be a smaller company.  As such, its tutorials seem to be running a few versions behind and are outdated at times with respect to variable names and template structures.&lt;/p&gt;

&lt;p&gt;We start off by grabbing and installing the latest version of Serverless (2.37.0 as of April 2021):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-o-&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; https://slss.io/install | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which will result in modifications to our login scripts and installation of &lt;code&gt;serverless&lt;/code&gt; into &lt;code&gt;$HOME/.serverless&lt;/code&gt; with output similar to:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GLIHcklF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/njanbn5yf8rjr7qh8xri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GLIHcklF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/njanbn5yf8rjr7qh8xri.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note we can uninstall (assuming we are not using Docker) by running &lt;code&gt;serverless uninstall&lt;/code&gt;.  As your current shell likely won't pick up these changes, you'll need to launch a new terminal before continuing.&lt;/p&gt;

&lt;p&gt;Switch to your desired base workspace directory.  Go ahead and run &lt;code&gt;serverless --version&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;serverless &lt;span class="nt"&gt;--version&lt;/span&gt;
Framework Core: 2.37.0 &lt;span class="o"&gt;(&lt;/span&gt;standalone&lt;span class="o"&gt;)&lt;/span&gt;
Plugin: 4.5.3
SDK: 4.2.2
Components: 3.8.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Conclusion
&lt;/h2&gt;

&lt;p&gt;And that's it for the time being.  &lt;/p&gt;

&lt;p&gt;Next time, we'll get our AWS account up and running, along with various NPM modules that we will be using for our builds.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>npm</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Background and Stack Description - Part 2 of Implementing a RESTful API on AWS</title>
      <dc:creator>Chris Straw</dc:creator>
      <pubDate>Sun, 11 Apr 2021 12:36:50 +0000</pubDate>
      <link>https://dev.to/cstraw/background-and-stack-description-2dca</link>
      <guid>https://dev.to/cstraw/background-and-stack-description-2dca</guid>
      <description>&lt;h2&gt;
  
  
  Impetus Behind This Project
&lt;/h2&gt;

&lt;p&gt;I started my formal software engineering career back in the 1990s at the search portal Excite@Home, where I was one of the primary engineers responsible for our internal server infrastructure. Over the last 20 years, I've experienced monolithic servers, the evolution of load balancer technology, the introduction of distributed applications running on cheap iron, the rise of virtual machines, and the off-loading of processing to clients via javascript and REST APIs.&lt;/p&gt;

&lt;p&gt;For almost a decade, I've been running my own consulting shop where I've had an internal J2EE-based monolithic server performing data analytics on terabytes of complex data.  My stack consisted of various J2EE EAR, WAR, and EJB components running on Wildfly mixed in with various Spring Boot modules providing REST APIs fronting a PrimeFaces-based JSF UI.  The components used technologies spanning a decade of evolution and ranging from JMX to JPA to Lucene to EJB injectors and EJB Remote client calls, all built with Maven, interfacing with SonarQube, covered by unit and integration test cases, and fronting a massive Postgresql database and millions of loose files.&lt;/p&gt;

&lt;p&gt;When COVID hit, I found myself with additional time and decided it was time for my internal project to sprout wings and fly out onto the Internet. In doing so, I discovered that my use-case would expose me to potentially tens of thousands of dollars in ongoing hosting and processing fees--clearly not something I relished taking on.  &lt;/p&gt;

&lt;p&gt;SOOO.... (and stop me if you have heard this before) in an effort to reduce costs, I decided to bite the bullet and explore the AWS/Azure/Google function-based "serverless" hosting solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reasoning Behind My Adoption of Serverless Framework and JS
&lt;/h2&gt;

&lt;p&gt;Despite my dislike for what I've always viewed as unstructured "script-kiddie" solutions (e.g. Perl, Python, Javascript, etc.), the case for moving as many components as I could away from the process/memory intensive J2EE/Spring JVM solutions to a Node.js javascript architecture turned out to be overwhelming.&lt;/p&gt;

&lt;p&gt;Likewise, despite my strong resistance to and serious reservations relating to leaving behind the structured data world of relational databases, the value premise underlying key-value pair data storage was impossible to refute.  This was made doubly so by the inherently dis-coupled nature of the data in what I personally deem a properly structured REST API.&lt;/p&gt;

&lt;p&gt;Unfortunately, I had become quite fond of Java's standardized JPA interfaces and Spring Boot's de-facto standardized Repository data access interfaces.  The key-value storage solutions of DynamoDB and MongoDB lacked basic support for this functionality.  Instead, one has to piece together different modules from all over the Internet, which each experiences different levels of support and continued development.&lt;/p&gt;

&lt;p&gt;After a period of searching and evaluation, I eventually decided to move forward with a Typescript/Javascript/Node.js solution using (1) Serverless Framework for creating and tearing down the Cloud infrastructure; (2) a DynamoDB for data storage; (3) a Dynamoose interface for interacting with the database; (4) Jest as my unit testing engine; and (5) a React front-end.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>cognito</category>
      <category>rest</category>
    </item>
    <item>
      <title>Series Summary - Part 1 of Implementing a RESTful API on AWS</title>
      <dc:creator>Chris Straw</dc:creator>
      <pubDate>Sun, 11 Apr 2021 12:29:31 +0000</pubDate>
      <link>https://dev.to/cstraw/a-detailed-step-by-step-implementation-of-a-full-featured-restful-api-on-aws-by-a-reformed-j2ee-engineer-jc9</link>
      <guid>https://dev.to/cstraw/a-detailed-step-by-step-implementation-of-a-full-featured-restful-api-on-aws-by-a-reformed-j2ee-engineer-jc9</guid>
      <description>&lt;p&gt;In this series of articles, I intend to provide a detailed, accurate, and step-by-step explanation of how to implement a RESTful web interface using a stack of &lt;a href="https://www.typescriptlang.org"&gt;Typescript&lt;/a&gt;, &lt;a href="https://nodejs.org/"&gt;Node.js&lt;/a&gt;, &lt;a href="https://dynamoosejs.com/"&gt;Dynamoose&lt;/a&gt;, &lt;a href="https://aws.amazon.com/dynamodb/"&gt;DynamoDB&lt;/a&gt;, &lt;a href="https://jestjs.io"&gt;Jest&lt;/a&gt;, &lt;a href="https://www.serverless.com"&gt;Serverless Framework&lt;/a&gt;, &lt;a href="https://aws.amazon.com"&gt;AWS&lt;/a&gt;, and &lt;a href="https://aws.amazon.com/cognito/"&gt;Amazon Cognito&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The final product includes everything one would expect from a RESTful API, including &lt;strong&gt;group-based&lt;/strong&gt; restrictions on DELETE, PUT and POST operations &lt;strong&gt;without&lt;/strong&gt; the use of &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html"&gt;custom lambda authorizer functions&lt;/a&gt; (yes, this is possible and I'll take you step-by-step through the process).&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;This Overview&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cstraw/background-and-stack-description-2dca"&gt;Background and project stack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cstraw/tool-installation-and-initial-configuration-part-3-of-implementing-a-restful-api-on-aws-kl9"&gt;Initial local tool installation and setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cstraw/amazon-web-services-sign-up-configuration-part-4-of-implementing-a-restful-api-on-aws-4f1d"&gt;Amazon Web Services sign-Up and configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cstraw/file-types-purposes-and-directory-skeleton-no2"&gt;File types, purposes, and directory skeleton&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[First build to ensure proper configuration]&lt;/li&gt;
&lt;li&gt;[Get our debugger and offline environment up and running]&lt;/li&gt;
&lt;li&gt;[Fleshing out our basic endpoints]&lt;/li&gt;
&lt;li&gt;[Bring online unit, integration, and coverage testing]&lt;/li&gt;
&lt;li&gt;[Incorporating database support]&lt;/li&gt;
&lt;li&gt;[Mocking our various components]&lt;/li&gt;
&lt;li&gt;[Adding in Cognito-based user authentication and groups]&lt;/li&gt;
&lt;li&gt;[Activating AWS IAm group-based authorization without the use of custom authorizers]&lt;/li&gt;
&lt;li&gt;[Github repository]&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>rest</category>
      <category>cognito</category>
    </item>
  </channel>
</rss>
