<?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: Joshua Kahn</title>
    <description>The latest articles on DEV Community by Joshua Kahn (@joshuaakahn).</description>
    <link>https://dev.to/joshuaakahn</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%2F219525%2Ff7eea009-4415-4861-9e67-96823b4dfcb7.jpg</url>
      <title>DEV Community: Joshua Kahn</title>
      <link>https://dev.to/joshuaakahn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joshuaakahn"/>
    <language>en</language>
    <item>
      <title>Exploring API Gateway Lambda Authorizers</title>
      <dc:creator>Joshua Kahn</dc:creator>
      <pubDate>Tue, 08 Sep 2020 16:24:00 +0000</pubDate>
      <link>https://dev.to/joshuaakahn/exploring-api-gateway-lambda-authorizers-1npa</link>
      <guid>https://dev.to/joshuaakahn/exploring-api-gateway-lambda-authorizers-1npa</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;More &lt;a href="https://www.swyx.io/writing/learn-in-public/"&gt;“learning in public”&lt;/a&gt;, capturing knowledge that will be useful for myself and others.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Over the past few weeks, I have spent quite a bit more time discussing &lt;a href="https://aws.amazon.com/api-gateway/"&gt;Amazon API Gateway&lt;/a&gt; than I have in years. API Gateway currently offers three types of APIs: (1) REST, (2) HTTP, and (3) WebSocket. The REST and HTTP flavors have quite a bit of overlap, with the HTTP option being the new generation with a growing set of capabilities (while driving towards parity with REST).&lt;/p&gt;

&lt;p&gt;In working with APIs, authorization is often a key concern. Unless you are building a truly public API, some level of authorization will be needed to control or limit access to the API. API Gateway offers several options that allow developers to separate authorization from business logic. While these differ dependent on the type of API, options include AWS IAM, &lt;a href="https://aws.amazon.com/cognito/"&gt;Amazon Cognito&lt;/a&gt;, OpenID Connect, and &lt;a href="https://aws.amazon.com/lambda/"&gt;AWS Lambda&lt;/a&gt; authorization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html"&gt;Lambda authorizers&lt;/a&gt; are particularly interesting given the flexiblity they can provide. A Lambda Authorizer is a a Lambda function to which API Gateway will defer authorization decisions. The function receives one of two types of &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-input.html"&gt;inputs&lt;/a&gt; and responds with &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html"&gt;output&lt;/a&gt; that includes a policy statement. As with other API Gateway features, separating authorization to its own function allows developers to focus on writing business logic.&lt;/p&gt;

&lt;p&gt;While Lambda authorizers can be useful, consider the requirements for your service before implementing universally. Other authorizer types may be more appropriate. For example, consider AWS IAM authorization for service-to-service calls or Cognito User Pool authoizers when using Cognito. Lambda Authorizers will introduce latency when called as the authorization logic will need to be executed before returning a response. API Gateway attempts to mitigate this latency by optionally caching the response for up to one hour. When cached, API Gateway will not call the authorizer function on subsequent requests.&lt;/p&gt;

&lt;p&gt;A Lambda authorizer can take one of two forms: (1) token-based and (2) request parameter-based. The type of authorizer dictates the event payload received by the Lambda function when invoked by API Gateway. The token-based authorizer (&lt;code&gt;TOKEN&lt;/code&gt;) receives the caller’s identity encoded as a bearer token (e.g. JWT or OAuth). A request parameter-based authorizer (&lt;code&gt;REQUEST&lt;/code&gt;) receives the complete request, including headers, query string parameters, and API Gateway context information. Which you select is determined by the information required to make an authorization decision.&lt;/p&gt;

&lt;p&gt;The response from a Lambda authorizer is composed primarily of a policy statement, not unlike an IAM policy. The policy describes the API resources the caller has access to. Resources are described using an ARN, meaning the authorization can have very fine-grained control over access to various APIs, stages, and/or resources. Wildcards are also available, but be careful so as not to provide inadvertent access. In addition to a policy, the authorizer response can also contain two fields, &lt;code&gt;context&lt;/code&gt; and &lt;code&gt;usageIdentifierKey&lt;/code&gt;. The &lt;code&gt;context&lt;/code&gt; map can be used to pass additional information to the backend service. For example, &lt;code&gt;context&lt;/code&gt; could contain details about the caller retrieved by the authorizer from a database lookup. If the API has a &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-usage-plans.html"&gt;usage plan&lt;/a&gt;, the &lt;code&gt;usageIdentifierKey&lt;/code&gt; is an API key associated with that plan.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Looking to go deeper? See Alex DeBrie’s excellent article &lt;a href="https://www.alexdebrie.com/posts/lambda-custom-authorizers/"&gt;The Complete Guide to Custom Authorizers with AWS Lambda and API Gateway&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Building a sample project
&lt;/h2&gt;

&lt;p&gt;To better understand Lambda authorizers, doing as I often do, I built a sample project. The premise of the project is an affiliate API for a book seller.&lt;/p&gt;

&lt;p&gt;On signing up, affiliates are provides with a means to authenticate with the book seller’s identity provider (IdP). The authentication mechanism is out of scope and does not matter. When an affiliate successfully authenticates, he receives a &lt;a href="http://jwt.io"&gt;JWT&lt;/a&gt; token encoded with identifying data, including a unique affiliate identifier (&lt;code&gt;orgId&lt;/code&gt;). The affiliate uses the JWT token to access the API by passing it in the &lt;code&gt;Authorization&lt;/code&gt; header as a bearer token.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Complete sample code for this project can be found on &lt;a href="https://github.com/jkahn117/aws-apigateway-custom-authorizer"&gt;GitHub&lt;/a&gt;. Details on deploying the project yourself are included.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s take a deeper look at the Lamdba authorizer included in the project (&lt;code&gt;custom-authorizer/app.rb&lt;/code&gt;). The authorizer is a typical Lambda function, wherein the &lt;code&gt;handler&lt;/code&gt; method is called on invocation. For our use case, the function performs the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Decodes the JWT token received in the incoming event payload.&lt;/li&gt;
&lt;li&gt;Checks if the token represents an administrator or an affiliate.&lt;/li&gt;
&lt;li&gt;If an affiliate, look up the affiliate in a DynamoDB table using the &lt;code&gt;orgId&lt;/code&gt; included in the token.&lt;/li&gt;
&lt;li&gt;Builds an authorization policy applicable to the caller. If an affiliate, various affiliate attributes are included in the &lt;code&gt;context&lt;/code&gt; map.&lt;/li&gt;
&lt;li&gt;Returns the policy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;API Gateway then uses the returned policy to determine if the caller can access the called API method. The authorizer result is cached for five minutes.&lt;/p&gt;

&lt;p&gt;The API methods available in the project are simplistic, primarily returning static data. The &lt;code&gt;add-affiliate&lt;/code&gt; function performs the task of creating a new affiliate in the DynamoDB table, creating an API key, and associating that key with a usage plan. A real-world onboarding process is likely more complex, but this was sufficient for a sample.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To enable sharing of common resources and libraries, this project makes use of &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html"&gt;Lambda Layers&lt;/a&gt;. For a deeper dive on Layers, specifically for Ruby, see my earlier &lt;a href="https://blog.iamjkahn.com/2019/02/exploring-aws-lambda-layers-and-ruby-support.html"&gt;blog post&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Taking the API for a spin
&lt;/h3&gt;

&lt;p&gt;We can use &lt;a href="https://www.postman.com"&gt;Postman&lt;/a&gt;, cURL, or a similar tool to exercise the sample project.&lt;/p&gt;

&lt;p&gt;First, we will act as an administrator to configure our first affiliate. We will use the &lt;code&gt;POST /admin/add&lt;/code&gt; endpoint to add a new affiliate, passing a request body such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "New Affiliate",
  "plan": "GOLD"
}

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



&lt;p&gt;If we attempt the request now, it will fail (unauthorized) as we have not provided a JWT token in the &lt;code&gt;Authorization&lt;/code&gt; header. Let’s add a bearer token in the &lt;code&gt;Authorization&lt;/code&gt; header that specifies the user is an administrator. Again, we’re not concerned with the creation of this token here, only that it is issued by a valid source.&lt;/p&gt;

&lt;p&gt;You can create your own token at &lt;a href="http://jwt.io"&gt;http://jwt.io&lt;/a&gt; or use the one provided below (the payload should contain a field called &lt;code&gt;admin&lt;/code&gt; which is set to a value of &lt;code&gt;true&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkkgYW0gQURNSU4iLCJpYXQiOjE1MTYyMzkwMjIsImFkbWluIjp0cnVlfQ.CiYHMxM1x1y7YGCn1NPpXP8JI006kPSxBVqD58Tgv3o

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



&lt;p&gt;Attempting the request again with the header results in the new affiliate being created (the &lt;code&gt;orgId&lt;/code&gt; value will vary):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "message": "Affiliate New Affiliate created! An API Key has been provisioned.",
  "name": "New Affiliate",
  "plan": "GOLD",
  "orgId": "81c95682-104a-4567-9ff5-e0af794d392e"
}

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



&lt;p&gt;We now have an affiliate account that can be used to access other API methods. Grab the &lt;code&gt;orgId&lt;/code&gt; and create a new JWT token, removing the &lt;code&gt;admin&lt;/code&gt; field and adding &lt;code&gt;orgId&lt;/code&gt; with the value found in the previous step. Set the secret key to &lt;code&gt;my-secret-key&lt;/code&gt; (shhhh, very secret) as shown in the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rAbqsEXl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://blog.iamjkahn.com/assets/images/2020-09-08/jwt_creation.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rAbqsEXl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://blog.iamjkahn.com/assets/images/2020-09-08/jwt_creation.png" alt="JWT Creation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Return to Postman. We’ll test an affiliate endpoint at &lt;code&gt;GET /products&lt;/code&gt;. Be sure to also update the &lt;code&gt;Authorization&lt;/code&gt; header with the new token (remove the old body payload).&lt;/p&gt;

&lt;p&gt;The result will include an array of books, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
  {
      "id": 12,
      "title": "A book",
      "author": "By someone",
      "price": 8.99
  },
  ...
]

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



&lt;p&gt;If you remove the token from the header, you will receive an &lt;code&gt;Unauthorized&lt;/code&gt; response.&lt;/p&gt;

&lt;h3&gt;
  
  
  A light load test
&lt;/h3&gt;

&lt;p&gt;Before closing this post, I wanted to perform a light load test on the API to confirm usage plans were enforced when a Lambda authorizer provided the API Key. To do so, I used &lt;a href="https://artillery.io/"&gt;Artillery&lt;/a&gt; with a simple scenario that simulates a small number of requests per second over one minute. This is not a true load test as much as a means to verify usage plan behavior. The usage plan limits are set artificially low.&lt;/p&gt;

&lt;p&gt;The Artillery configuration is simple: call the two affiliate endpoints at a rate of 15 requests per second for one minute. Because the usage plan limits the client to five requests per second, I expected that roughly two-thirds of the requests would yield a 429 response (To Many Requests). The Artillery configuration is as follows (note the bearer token in the &lt;code&gt;Authorization&lt;/code&gt; header, I precomputed it using &lt;a href="http://jwt.io"&gt;http://jwt.io&lt;/a&gt; for the affiliate &lt;code&gt;OrgId&lt;/code&gt; created earlier):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config:
  target: "https://abcdefg.execute-api.us-east-1.amazonaws.com/dev"
  phases:
    - duration: 60
      arrivalRate: 15
  defaults:
    headers:
      Authorization: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik5ldyBBZmZpbGlhdGUiLCJpYXQiOjE1MTYyMzkwMjIsIm9yZ0lkIjoiODFjOTU2ODItMTA0YS00NTY3LTlmZjUtZTBhZjc5NGQzOTJlIn0.-9tXCDNaAXpOGSlek7ENpMjuFXq1yzWfXmBJUgCtQ3Q"
scenarios:
  - flow:
    - get:
        url: "/products"
    - get:
        url: "/products/1"

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



&lt;p&gt;The result showed that &lt;em&gt;all&lt;/em&gt; requests succeeded, meaning that Usage Plan throttling &lt;em&gt;did not work&lt;/em&gt;. After some digging, I came to realize that the &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-key-source.html"&gt;source of the API key&lt;/a&gt; was inccorrect. By default, API Key Source is set to &lt;code&gt;HEADER&lt;/code&gt;, but here we need to change to &lt;code&gt;AUTHORIZER&lt;/code&gt;. While available in the API Gateway Console, SAM does not have a property to change this setting (though &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-apikeysourcetype"&gt;CloudFormation does&lt;/a&gt;). Each deployment of the serverless application also resets the Key Source, meaning we either need to reset via the AWS CLI/Console after each deployment or use an OpenAPI specification.&lt;/p&gt;

&lt;p&gt;For now, I’ve elected to manually configure the Key Source in the AWS Console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OUf1LAXZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://blog.iamjkahn.com/assets/images/2020-09-08/apigw_apikeysource_setting.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OUf1LAXZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://blog.iamjkahn.com/assets/images/2020-09-08/apigw_apikeysource_setting.png" alt="API Key Source Setting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Key Source setting fixed, we can run the “load test” again. Looking at just the first ten seconds, we see that roughly fifty requests are allowed, which aligns with the GOLD usage plan rate of five requests per second. Over the course of the next two ten-second periods, the client exhausts the 100 requests allowed by the usage plan per day (set purposefully low for this demonstration) and all subsequent requests are blocked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Started phase 0, duration: 60s @ 11:19:47(-0500) 2020-09-08
Report @ 11:19:57(-0500) 2020-09-08
Elapsed time: 10 seconds
  Scenarios launched: 149
  Scenarios completed: 147
  Requests completed: 295
  Mean response/sec: 30
  Response time (msec):
    min: 43.4
    max: 2862.7
    median: 92.6
    p95: 1849.3
    p99: 2197.4
  Codes:
    200: 56
    429: 239

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



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

&lt;p&gt;Building a more complex Lambda authorizer was useful in building my own understanding of how they can be used in a broader serverless application. For a deeper dive, I recommend Alex DeBrie’s excellent article &lt;a href="https://www.alexdebrie.com/posts/lambda-custom-authorizers/"&gt;The Complete Guide to Custom Authorizers with AWS Lambda and API Gateway&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Complete sample code for this project can be found on &lt;a href="https://github.com/jkahn117/aws-apigateway-custom-authorizer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@scottwebb"&gt;Scott Webb&lt;/a&gt; on &lt;a href="https://unsplash.com/"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post first appeared at &lt;a href="https://blog.iamjkahn.com/2020/09/exploring-api-gateway-custom-authorizers.html"&gt;https://blog.iamjkahn.com/2020/09/exploring-api-gateway-custom-authorizers.html&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Starting an AWS Step Functions State Machine from Java</title>
      <dc:creator>Joshua Kahn</dc:creator>
      <pubDate>Mon, 27 Jan 2020 18:41:00 +0000</pubDate>
      <link>https://dev.to/joshuaakahn/starting-an-aws-step-functions-state-machine-from-java-5ci7</link>
      <guid>https://dev.to/joshuaakahn/starting-an-aws-step-functions-state-machine-from-java-5ci7</guid>
      <description>&lt;p&gt;Just over two years ago, I wrote a quick post to document &lt;a href="///2017/11/invoking-an-aws-lambda-function-from-java.html"&gt;how to invoke an AWS Lambda function from Java&lt;/a&gt;. I recently was asked how to start execution of an AWS Step Function state machine and also found a working example challenging to dig up … so I put together a quick example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.amazonaws.regions.Regions;
import com.amazonaws.services.stepfunctions.AWSStepFunctions;
import com.amazonaws.services.stepfunctions.AWSStepFunctionsClientBuilder;
import com.amazonaws.services.stepfunctions.model.StartExecutionRequest;
import com.amazonaws.services.stepfunctions.model.StartExecutionResult;
import org.json.JSONObject;

// ...

// (1) Define the AWS Region in which the function is to be invoked.
Regions region = Regions.fromName(System.getenv("AWS_REGION"));

// (2) Instantiate AWSStepFunctionsClientBuilder to build the client
AWSStepFunctionsClientBuilder builder = AWSStepFunctionsClientBuilder.standard()
                                          .withRegion(region);

// (3) Build the client, which will ultimately do the work
AWSStepFunctions client = builder.build();

// (4) Construct the JSON input to the state machine
JSONObject sfnInput = new JSONObject();
sfnInput.put("key1", "hello");
sfnInput.put("key2", "world");

// (5) Create a request to start execution with needed parameters
StartExecutionRequest request = new StartExecutionRequest()
                                      .withStateMachineArn("MY_STATE_MACHINE_ARN")
                                      .withInput(sfnInput.toString());

// (6) Start the state machine and capture response
StartExecutionResult result = client.startExecution(request);

// (7) Handle the result, this includes the execution ID

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



&lt;p&gt;The example above makes use of the &lt;code&gt;DefaultAWSCredentialsProviderChain&lt;/code&gt; to pull credentials from environment variables, instance profile, etc. You can use &lt;code&gt;BasicAWSCredentials&lt;/code&gt; if you need to hardcode keys, but this is a much less desirable option.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Securely Storing API Secrets for AWS AppSync HTTP Data Sources</title>
      <dc:creator>Joshua Kahn</dc:creator>
      <pubDate>Wed, 08 Jan 2020 01:29:00 +0000</pubDate>
      <link>https://dev.to/joshuaakahn/securely-storing-api-secrets-for-aws-appsync-http-resolvers-2j98</link>
      <guid>https://dev.to/joshuaakahn/securely-storing-api-secrets-for-aws-appsync-http-resolvers-2j98</guid>
      <description>&lt;p&gt;At AWS re:Invent 2019, I presented a &lt;a href="https://d1.awsstatic.com/events/reinvent/2019/REPEAT_2_AWS_AppSync_does_that_Support_for_alternative_data_sources_MOB318-R2.pdf"&gt;Chalk Talk on alternative data sources for AWS AppSync&lt;/a&gt;. During one repeat of the session, an attendee asked about storing API Keys for web services. The attendee specifically referenced &lt;a href="https://www.algolia.com/"&gt;Algolia&lt;/a&gt;, though numerous services use API Keys to identify the number and frequency of calls from a particular user.&lt;/p&gt;

&lt;p&gt;To build an AWS AppSync &lt;a href="https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-http-resolvers.html"&gt;HTTP Resolver&lt;/a&gt; to “GraphQL-ify” a service that uses API Keys, it would be easy to hardcode the key in the request resolver. Resolvers are not exposed to the end user of the API, but they are committed to source control, which could potentially leak API Keys. An application may also use different API Keys in different environments, for example to allow for higher throughput in production.&lt;/p&gt;

&lt;p&gt;This post discusses an approach to securely storing and using API Keys by leveraging &lt;a href="https://docs.aws.amazon.com/appsync/latest/devguide/pipeline-resolvers.html"&gt;Pipeline Resolvers&lt;/a&gt;. API Keys are stored in &lt;a href="https://aws.amazon.com/secrets-manager/"&gt;AWS Secrets Manager&lt;/a&gt; and injected into the request to the downstream API.&lt;/p&gt;

&lt;p&gt;To demonstrate, I extended the &lt;a href="https://adrianhall.github.io/cloud/2018/07/20/build-a-graphql-weather-api-with-openweathermap-and-aws-appsync/"&gt;GraphQL Weather API built by Adrian Hall&lt;/a&gt;. Adrian built an API using &lt;a href="https://openweathermap.org/"&gt;OpenWeatherMap&lt;/a&gt;, which uses API keys, as an HTTP data source. Here, I’ve used the same GraphQL schema and resolvers for interacting with OpenWeatherMap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Pipeline Resolver
&lt;/h2&gt;

&lt;p&gt;The Pipeline Resolver for my weather API is composed of two stages: (1) retrieve secret value from Secrets Manager and (2) query OpenWeatherMap. We can define the resolver using &lt;a href="https://aws.amazon.com/cloudformation/"&gt;AWS CloudFormation&lt;/a&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WeatherByCityQueryResolver:
  Type: AWS::AppSync::Resolver
  Properties:
    ApiId: !GetAtt WeatherApi.ApiId
    TypeName: Query
    FieldName: weatherByCity
    Kind: PIPELINE
    PipelineConfig:
      Functions:
        - !GetAtt GetSecretValue.FunctionId # (1) get secret value
        - !GetAtt GetWeatherByCity.FunctionId # (2) query OpenWeatherApi
    RequestMappingTemplate: |
      $util.qr($ctx.stash.put("SecretId", "/sample/openweathermap/apikey"))
      {}
    ResponseMappingTemplate: |
      $util.toJson($ctx.result)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We’ll take a deeper look at the two functions that compose the resolver shortly, but take note of the request mapping template. Here, we use the AppSync &lt;code&gt;stash&lt;/code&gt; (a map that lives through a single resolver execution) to store the unique name of the secret in Secrets Manager. The secret name is hardcoded in the request mapping template, but by elevating that name to the top of the pipeline, our &lt;code&gt;GetSecretValue&lt;/code&gt; function is more flexible. We could pass the name of any arbitrary secret (presuming AppSync has permission to access it) and retrieve the secret value with the one function.&lt;/p&gt;

&lt;p&gt;For this example, the OpenWeatherMap API Key is stored in Secrets Manager with the name &lt;code&gt;/sample/openweathermap/apikey&lt;/code&gt;. To implement this solution on your own, you will need to sign-up for the OpenWeatherMap service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting the Secret Value
&lt;/h3&gt;

&lt;p&gt;In an earlier &lt;a href="https://blog.iamjkahn.com/2019/12/invoking-even-more-aws-services-directly-from-aws-appsync.html"&gt;blog post&lt;/a&gt;, I described how to invoke various AWS services directly from AWS AppSync, including Secrets Manager. The &lt;code&gt;GetSecretValue&lt;/code&gt; function is almost identical to the resolver described in that post, though here the caller passes the name of the secret in the &lt;code&gt;stash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In CloudFormation, the function is configured as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GetSecretValue:
  Type: AWS::AppSync::FunctionConfiguration
  Properties:
    ApiId: !GetAtt WeatherApi.ApiId
    Name: GetSecretValue
    Description: &amp;gt;
      Retrieves the value of the specified secrets from
      AWS Secrets Manager.
    DataSourceName: !GetAtt SecretsManagerDataSource.Name
    FunctionVersion: "2018-05-29"
    RequestMappingTemplate: |
      {
        "version": "2018-05-29",
        "method": "POST",
        "resourcePath": "/",
        "params": {
          "headers": {
            "content-type": "application/x-amz-json-1.1",
            "x-amz-target": "secretsmanager.GetSecretValue"
          },
          "body": {
            "SecretId": "$ctx.stash.SecretId"
          }
        }
      }
    ResponseMappingTemplate: |
      #set( $result = $util.parseJson($ctx.result.body) )
      $util.toJson($result.SecretString)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As noted in my previous post as well, it is extremely important to configure the HTTP Data Source to sign requests that invoke AWS Services. We also need to provide an AppSync service role with permissions to get the secret (&lt;code&gt;secretsmanager:GetSecretValue&lt;/code&gt;). Again, in CloudFormation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SecretsManagerDataSource:
  Type: AWS::AppSync::DataSource
  Properties:
    ApiId: !GetAtt WeatherApi.ApiId
    Name: SecretsManager
    Description: AWS Secrets Manager
    Type: HTTP
    ServiceRoleArn: !GetAtt AppSyncServiceRole.Arn
    HttpConfig:
      Endpoint: !Sub "https://secretsmanager.${AWS::Region}.amazonaws.com/"
      AuthorizationConfig:
        AuthorizationType: AWS_IAM
        AwsIamConfig:
          SigningRegion: !Sub "${AWS::Region}"
          SigningServiceName: secretsmanager
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Querying OpenWeatherMap
&lt;/h3&gt;

&lt;p&gt;Armed with the secret API Key, we can call the OpenWeatherAPI. Both the Data Source and response mapping template are identical to Adrian’s article; however, we need to slightly modify the request mapping to use the API key retrieved in the previous function. The request mapping template is as follows (note the use of &lt;code&gt;$ctx.prev.result&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "version": "2018-05-29",
  "method": "GET",
  "resourcePath": "/data/2.5/weather",
  "params":{
    "query": {
      "q": "$context.args.city",
      "appid": "$ctx.prev.result"
    },
    "headers": {
      "Content-Type": "application/json"
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;By using a Pipeline Resolver that directly invokes Secrets Manager, we have alleviated the need to hardcode a secret and secured it using IAM permissions. We also did so without writing a line of code … well, just a few Velocity Templates, which are very easy to maintain. Our new API allows us to query for the current weather in Nashville (or many other cities):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query Weather {
  weatherByCity(city: "Nashville") {
    timestamp
    temperature
    location
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "data": {
    "weatherByCity": {
      "timestamp": "2020-01-07T22:55:43Z",
      "temperature": 48.18,
      "location": "Nashville, US"
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;While I’m not sure if the re:Invent attendee who inspired this post will find it, I hope you have found it useful. Similar approaches can also be used to build more complex data retrievals as well, without the need to write code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@johnwestrock?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Dave&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/weather?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>awsappsync</category>
      <category>graphql</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Invoking even more AWS services directly from AWS AppSync</title>
      <dc:creator>Joshua Kahn</dc:creator>
      <pubDate>Mon, 09 Dec 2019 21:58:00 +0000</pubDate>
      <link>https://dev.to/joshuaakahn/invoking-even-more-aws-services-directly-from-aws-appsync-19gc</link>
      <guid>https://dev.to/joshuaakahn/invoking-even-more-aws-services-directly-from-aws-appsync-19gc</guid>
      <description>&lt;p&gt;A few months ago, I wrote a &lt;a href="https://aws.amazon.com/blogs/mobile/invoke-aws-services-directly-from-aws-appsync/"&gt;post on the AWS Mobile Blog&lt;/a&gt; that demonstrated how to invoke AWS service directly from AWS AppSync. In that case, I specifically focused on AWS Step Functions, but it is possible to integrate AppSync with many other AWS services. The goal of this post is to document the integration of AppSync with services beyond Step Functions.&lt;/p&gt;

&lt;p&gt;AWS AppSync uses GraphQL resolvers to define the interaction between AppSync and each data source. These are Apache Velocity Templates that will be unique per GraphQL operation. By moving integration of AWS services to resolvers, we can minimize the maintenance of integration code. Velocity Templates generally require little upkeep over time. This approach can be even more maintainable than relying on a thin layer of Lambda code for integration, which would still require dependency management and updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding an AWS data source
&lt;/h2&gt;

&lt;p&gt;The first step in integrating AppSync with an AWS service is to create an HTTP data source for the service. For an AWS service, the data source endpoint is set to the service API endpoint for the given AWS region and we configure &lt;a href="https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html"&gt;SigV4&lt;/a&gt; signing.&lt;/p&gt;

&lt;p&gt;Currently, to configure signing of HTTP data sources, we can use either the AWS CLI or CloudFormation. My preference is to utilize CloudFormation for these needs, though my earlier blog post demonstrates the CLI approach as well. For example, we can add a new data source to invoke Amazon SQS using CloudFormation as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SQSHttpDataSource:
  Type: AWS::AppSync::DataSource
  Properties:
    ApiId: !GetAtt MyApi.ApiId
    Name: SQSDataSource
    Description: SQS Data Source
    Type: HTTP
    # IAM role defined elsewhere in AWS CloudFormation template
    # Note: this role needs a policy with 'sqs:SendMessage' permission
    ServiceRoleArn: !GetAtt AppSyncServiceRole.Arn
    HttpConfig:
      Endpoint: !Sub https://sqs.${AWS::Region}.amazonaws.com/
      AuthorizationConfig:
        AuthorizationType: AWS_IAM
        AwsIamConfig:
          SigningRegion: !Ref AWS::Region
          SigningServiceName: sqs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;AppSync will require an AWS IAM role that allows the service to perform the desired action. For example, SQS would require &lt;code&gt;sqs:SendMessage&lt;/code&gt; permission and Step Functions &lt;code&gt;states:StartExecution&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After creating the data source, we can implement the resolvers that allow interaction with the AWS service. Let’s step through a few example integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Amazon SQS
&lt;/h2&gt;

&lt;p&gt;For each service reviewed in this post, we will start with a sample GraphQL schema that defines the interactions and data associated with the resolver.&lt;/p&gt;

&lt;p&gt;We will begin with Amazon Simple Queue Service (SQS), one of the earliest AWS services and one of my favorites for building reliable, decoupled workloads. Here, we send a messsage via a queue, though other operations are available as well. For example, we could list all messages on a particular queue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input SendMessageInput {
  email: String!
  message: String!
}

type Message {
  id: ID!
  email: String!
  message: String!
}

type Mutation {
  sendMessage(input: SendMessageInput!): Message
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;AppSync can be used to deliver a message to an SQS Queue using the following resolver. While SQS also &lt;a href="https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-making-api-requests.html"&gt;supports a &lt;code&gt;POST&lt;/code&gt; API&lt;/a&gt; as well, I have implemented here using a &lt;code&gt;GET&lt;/code&gt;. Note that the endpoint resource path includes the AWS Account ID and name of the queue. Infrastructure as code approaches, such as CloudFormation, would make wiring this information easy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;sendMessage&lt;/code&gt; - Request Mapping&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "version": "2018-05-29",
  "method": "GET",
  "resourcePath": "/&amp;lt;ACCOUNT_ID&amp;gt;/&amp;lt;QUEUE_NAME&amp;gt;",
  "params": {
    "query": {
      "Action": "SendMessage",
      "Version": "2012-11-05",
      "MessageBody": "$util.urlEncode($util.toJson($ctx.args.input))"
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The response from SQS is encoded in XML and can be easily transformed to a JSON payload using the &lt;code&gt;$util&lt;/code&gt; functions provided by AppSync.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;sendMessage&lt;/code&gt; - Response Mapping&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#set( $result = $utils.xml.toMap($ctx.result.body) )
{
  "id": "$result.SendMessageResponse.SendMessageResult.MessageId",
  "email": "$ctx.args.input.email",
  "message": "$ctx.args.input.message",
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  AWS Secrets Manager
&lt;/h2&gt;

&lt;p&gt;AWS Secrets Manager allows customers to protect sensitive information such as API keys. In a future blog post, I will share how I incorporated Secrets Manager in an &lt;a href="https://docs.aws.amazon.com/appsync/latest/devguide/pipeline-resolvers.html"&gt;AWS AppSync Pipeline Resolver&lt;/a&gt; to first retrieve a secret API key before querying a third-party web service for data, all via AppSync resolvers. For now, we can simply retrieve and return a secret from Secrets Manager.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Query {
  getSecret(SecretName: String!): String
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;getSecret&lt;/code&gt; - Request Mapping&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "version": "2018-05-29",
  "method": "POST",
  "resourcePath": "/",
  "params": {
    "headers": {
      "content-type": "application/x-amz-json-1.1",
      "x-amz-target": "secretsmanager.GetSecretValue"
    },
    "body": {
      "SecretId": "$ctx.args.SecretName"
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The response from SQS is encoded in XML and can be easily transformed to a JSON payload using the &lt;code&gt;$util&lt;/code&gt; functions provided by AppSync.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;getSecret&lt;/code&gt; - Response Mapping&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#set( $result = $util.parseJson($ctx.result.body) )
$util.toJson($result.SecretString)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  AWS Step Functions
&lt;/h2&gt;

&lt;p&gt;Although I discussed Step Functions in the earlier mentioned blog, I will include starting a Step Functions state machine here for completeness and to document handling more complex input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Mutation {
  submitOrder(input: OrderInput!): Order
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;submitOrder&lt;/code&gt; - Request Mapping&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$util.qr($ctx.stash.put("orderId", $util.autoId()))
{
  "version": "2018-05-29",
  "method": "POST",
  "resourcePath": "/",
  "params": {
    "headers": {
      "content-type": "application/x-amz-json-1.0",
      "x-amz-target":"AWSStepFunctions.StartExecution"
    },
    "body": {
      "stateMachineArn": "&amp;lt;STATE_MACHINE_ARN&amp;gt;",
      "input": "$util.escapeJavaScript($util.toJson($input))"
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;sumitOrder&lt;/code&gt; - Response Mapping&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "id": "${ctx.stash.orderId}"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Please let me know if there are other integrations you would be interested in seeing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Originally published at &lt;a href="https://blog.iamjkahn.com"&gt;https://blog.iamjkahn.com&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Photo by Patrick Perkins on Unsplash&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>awsawsappsync</category>
    </item>
    <item>
      <title>Building AWS AppSync Pipeline Resolvers with AWS CloudFormation</title>
      <dc:creator>Joshua Kahn</dc:creator>
      <pubDate>Mon, 11 Mar 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/joshuaakahn/building-aws-appsync-pipeline-resolvers-with-aws-cloudformation-1fjg</link>
      <guid>https://dev.to/joshuaakahn/building-aws-appsync-pipeline-resolvers-with-aws-cloudformation-1fjg</guid>
      <description>&lt;p&gt;Among the many updates from &lt;a href="https://aws.amazon.com/appsync/"&gt;AWS AppSync&lt;/a&gt; over the past few months, the addition of &lt;a href="https://docs.aws.amazon.com/appsync/latest/devguide/pipeline-resolvers.html"&gt;Pipeline Resolvers&lt;/a&gt; was particularly exciting. Pipeline Resolvers allow us to build a resolver from a series of reusable functions, each of which can query a separate data source. This approach can be useful in performing an authorization check or resolving a batch request across data sources.&lt;/p&gt;

&lt;p&gt;For example, I recently built a Pipeline Resolver composed of two functions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieves a list of recent items, each identified by a unique ID, from &lt;a href="https://aws.amazon.com/elasticache/"&gt;Amazon ElastiCache&lt;/a&gt; via a AWS Lambda data source.&lt;/li&gt;
&lt;li&gt;Retrieves each of the items from an Amazon DynamoDB data source using BatchGetItem. Using a Pipeline Resolver allowed for separation of functionality as well as composition via AppSync.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Instead of reviewing how I built the resolver, in this post, I will share how I *built it using *&lt;a href="https://aws.amazon.com/cloudformation/"&gt;&lt;em&gt;AWS CloudFormation&lt;/em&gt;&lt;/a&gt;. If you are interested in an overview of Pipeline Resolvers or an example implementation, see the Resources section below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building a Pipeline Resolver with CloudFormation
&lt;/h3&gt;

&lt;p&gt;When building a Pipeline Resolver in CloudFormation, we specify a resolver as well as the functions that compose that resolver. The resolver and its composite functions will contain request and response mapping templates, but only the functions will have a data source. To demonstrate, we will implement theListPosts resolver found in Nader Dabit’s &lt;a href="https://medium.com/@dabit3/intro-to-aws-appsync-pipeline-functions-3df87ceddac1"&gt;Intro to AWS AppSync Pipeline Functions&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;First, we’ll implement the resolver. We’ll assume the AppSync API and other applicable resources have already been created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ListPostsQueryResolver:  
 Type: AWS::AppSync::Resolver  
 DependsOn: MySchema  
 Properties:
   ApiId: !GetAtt MyApi.ApiId  
   TypeName: Query  
   FieldName: listPosts  
   # configure this resolver as a pipeline  
   Kind: PIPELINE  
   PipelineConfig:  
     Functions:  
       - !GetAtt IsUserCallerFunction.FunctionId  
       - !GetAtt GetPostsFunction.FunctionId  
   # see Nader's article for details on these templates  
   RequestMappingTemplate: |  
     $util.qr($ctx.stash.put("callerId", $ctx.identity.sub))  
     $util.qr($ctx.stash.put("userId", $ctx.args.userId))  
     {}  
   ResponseMappingTemplate: |  
     $util.toJson($ctx.result)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, we will implement the first of two pipeline functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IsUserCallerFunction:  
 Type: AWS::AppSync::FunctionConfiguration  
 Properties:  
   ApiId: !GetAtt MyApi.ApiId  
   Name: is_user_caller  
   Description: Checks to see if the user is also the caller  
   DataSourceName: !GetAtt UsersDynamoDBDataSource.Name  
   FunctionVersion: "2018-05-29"  
   RequestMappingTemplate: |  
     #if($ctx.stash.callerId == $ctx.stash.userId)  
       #return($ctx.prev.result)  
     #else  
     {  
       "operation": "GetItem",  
       "key": {  
         "id": $util.dynamodb.toDynamoDBJson($ctx.stash.callerId),  
       }  
     }  
     #end  
   ResponseMappingTemplate: |  
     #if($ctx.result.level != "admin")  
       $util.error("User is not authorized to make this query")  
     #else  
     $util.toJson($ctx.result)  
     #end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, we’ll add the second function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GetPostsFunction:  
 Type: AWS::AppSync::FunctionConfiguration  
 Properties:  
   ApiId: !GetAtt MyApi.ApiId  
   Name: get_posts  
   Description: Scan table and retrieve items created by user  
   DataSourceName: !GetAtt PostsDynamoDBDataSource.Name  
   FunctionVersion: "2018-05-29"  
   RequestMappingTemplate: |  
     {  
       "operation" : "Scan",  
       "filter" : {  
         "expression" : "#userId = :userId",  
         "expressionNames" : {  
           "#userId" : "userId"  
         },  
         "expressionValues" : {  
           ":userId" : $util.dynamodb.toDynamoDBJson($ctx.stash.userId)  
         }  
       },  
       "nextToken": $util.toJson($util.defaultIfNullOrBlank($ctx.args.nextToken, null))  
     }  
   ResponseMappingTemplate: |  
     #if($ctx.error)  
       $util.error($ctx.error.message, $ctx.error.type)  
     #end  
     {  
       "items": $util.toJson($ctx.result.items),  
       "nextToken": $util.toJson($util.defaultIfNullOrBlank($context.result.nextToken, null))  
     }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After creating the CloudFormation stack, we can test the resolver via the AppSync Console. As usual, CloudFormation brings the value of reuse, portability, configurability.&lt;/p&gt;

&lt;p&gt;Thanks for reading and please feel free to leave a comment with any questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/@dabit3/intro-to-aws-appsync-pipeline-functions-3df87ceddac1"&gt;Intro to AWS AppSync Pipeline Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-pipeline-resolvers.html"&gt;Tutorial: Pipeline Resolvers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-reference-appsync.html"&gt;AWS AppSync Resource Types Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Understanding AWS Batch: A Brief Introduction and Sample Project</title>
      <dc:creator>Joshua Kahn</dc:creator>
      <pubDate>Mon, 14 May 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/joshuaakahn/understanding-aws-batch-a-brief-introduction-and-sample-project-3248</link>
      <guid>https://dev.to/joshuaakahn/understanding-aws-batch-a-brief-introduction-and-sample-project-3248</guid>
      <description>&lt;p&gt;Of late, I have focused most of my development work as being “serverless-first” — it I can build it with &lt;a href="https://aws.amazon.com/lambda/"&gt;AWS Lambda&lt;/a&gt;, I do. That said, there are some types of compute workloads that simply do not fit the serverless paradigm. In most cases, these tend to be long-running jobs or big data analysis that require multiple hours of ongoing work.&lt;/p&gt;

&lt;p&gt;Solutions built on &lt;a href="https://aws.amazon.com/batch/"&gt;AWS Batch&lt;/a&gt; allow developers to build efficient, long-running compute jobs by focusing on the business logic required, while AWS manages the scheduling and provisioning of the work. I recently undertook an investigation of Batch for a customer and built a &lt;a href="https://github.com/jkahn117/aws-batch-image-processor"&gt;sample project&lt;/a&gt; that I would like to share in this post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Brief Introduction to AWS Batch
&lt;/h3&gt;

&lt;p&gt;Batch computing run jobs asynchronously and automatically across multiple compute instances. While running a single job may be trivial, running many at scale, particularly with multiple dependencies, can be more challenging. This is where using a fully managed service such as AWS Batch offers significant benefit.&lt;/p&gt;

&lt;p&gt;AWS Batch organizes its work into four components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Jobs&lt;/strong&gt;  — the unit of work submitted to AWS Batch, whether it be implemented as a shell script, executable, or Docker container image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job Definition&lt;/strong&gt;  — describes how your work is be executed, including the CPU and memory requirements and IAM role that provides access to other AWS services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job Queues&lt;/strong&gt;  — listing of work to be completed by your Jobs. You can leverage multiple queues with different priority levels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute Environment &lt;/strong&gt; — the compute resources that run your Jobs. Environments can be configured to be managed by AWS or on your own as well as the number of and type(s) of instances on which Jobs will run. You can also allow AWS to select the right instance type. Lastly, a scheduler owned by AWS evaluated when and where to run Jobs that have been submitted to the Job Queues.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The sample project described in the following section defines each of the above (except for the scheduler) for our simple batch job. Our focus is solely on the development of business logic (to complete the batch work) and configuration of how that work is to be completed…AWS manages the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample Project: Image Processing
&lt;/h3&gt;

&lt;p&gt;AWS Batch can support a variety of resource intensive tasks, ranging from analyzing complex financial data to screening for drug interactions. That said, our sample is rather simple … processing and tagging an image via &lt;a href="https://aws.amazon.com/rekognition/"&gt;Amazon Rekogniton&lt;/a&gt; (yes, this could be a Lambda function, but we’re focused on Batch today).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OKql385P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://blog.iamjkahn.com/assets/images/1%2AkmsdH3HOpadg9ek3S25Qew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OKql385P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://blog.iamjkahn.com/assets/images/1%2AkmsdH3HOpadg9ek3S25Qew.png" alt="Sample project architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As images are put in an S3 bucket, a Lambda function is invoked, which will submit a new AWS Batch job. The job is implemented as a Docker container image, which is stored in &lt;a href="https://aws.amazon.com/ecr/"&gt;Amazon Elastic Container Registry (ECR)&lt;/a&gt;. Our job is a simple Ruby application that takes a set of command line arguments as input to its work. I’ve used &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt; to manage the infrastructure of this project (see &lt;a href="https://github.com/jkahn117/aws-batch-image-processor/blob/master/template.tf"&gt;template.tf&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;A few comments / learnings from my exploration into AWS Batch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Three different IAM Roles were required: (1) Batch service role; (2) EC2 instance role for underlying instances; and (3) ECS task role (to interact with DynamoDB and Rekognition). The task role will be most familiar as it defines the AWS services the job can interact with; however, the instance role is also important (use the &lt;em&gt;AmazonEC2ContainerServiceforEC2Role&lt;/em&gt; managed role).&lt;/li&gt;
&lt;li&gt;AWS Batch offers a &lt;a href="https://docs.aws.amazon.com/batch/latest/userguide/troubleshooting.html"&gt;troubleshooting guide&lt;/a&gt; to help with common issues. For example, I ran into “Jobs Stuck in RUNNABLE Status” due not using the aforementioned instance role.&lt;/li&gt;
&lt;li&gt;As part of the Job Definition, you can define both parameters and environment variables. I used parameters as values that I might override when creating the job and environment variables as values that should not be changed (e.g. AWS Region) but need to be passed to the job.&lt;/li&gt;
&lt;li&gt;The command defined in the Job Definition is similar to the Docker RUN command. Here, I chose to interact with my job via the command line, passing parameter values via the Job Definition command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For further details on implementation, please see my &lt;a href="https://github.com/jkahn117/aws-batch-image-processor"&gt;aws-batch-image-processor repository on GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Calling Amazon API Gateway Authenticated Methods with axios and aws4</title>
      <dc:creator>Joshua Kahn</dc:creator>
      <pubDate>Wed, 03 May 2017 00:00:00 +0000</pubDate>
      <link>https://dev.to/joshuaakahn/calling-amazon-api-gateway-authenticated-methods-with-axios-and-aws4-1hi8</link>
      <guid>https://dev.to/joshuaakahn/calling-amazon-api-gateway-authenticated-methods-with-axios-and-aws4-1hi8</guid>
      <description>&lt;p&gt;&lt;a href="https://aws.amazon.com/api-gateway/"&gt;Amazon API Gateway&lt;/a&gt; provides a convenient, easy-to-use service that allows developers to publish, monitor, and maintain APIs. It also provides a separation of concerns between your custom business logic and common needs such as caching, throttling, and authorization.&lt;/p&gt;

&lt;p&gt;For a recent project, I needed to secure my APIs such that only authorized users could call them (e.g. administrator endpoints). API Gateway supports a number of approaches to &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-to-api.html"&gt;controlling access to your services&lt;/a&gt;. I also needed to provide authentication for a pool of users and opted to leverage AWS’s powerful IAM capability to control access via &lt;a href="https://aws.amazon.com/cognito/"&gt;Amazon Cognito&lt;/a&gt;. Cognito provides both user management as well as federated identity to provide secure access to AWS resources, including &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/permissions.html"&gt;calling an API Gateway method&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enough background, on to the code…&lt;/p&gt;

&lt;p&gt;On the frontend, I used the popular &lt;a href="https://github.com/mzabriskie/axios"&gt;axios&lt;/a&gt; HTTP library in addition to &lt;a href="https://github.com/mhart/aws4"&gt;aws4&lt;/a&gt;, a library to sign requests using &lt;a href="https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html"&gt;AWS Signature v4&lt;/a&gt;. While the configuration of API Gateway is beyond the scope of this post, know that we need to sign and provide an &lt;code&gt;Authentication&lt;/code&gt; header in order for the call to be allowed by secured APIs. This is what aws4 helps to enable. Signing the requests allows the frontend to assume an AWS Role authorized to call the API.&lt;/p&gt;

&lt;p&gt;Note: the following code snippets assume the user has already authenticated via Cognito and retrieved temporary credentials (including an access key, secret key, and session token).&lt;/p&gt;

&lt;p&gt;First, the following code demonstrates a &lt;code&gt;GET&lt;/code&gt; to an API secured with &lt;code&gt;AWS_IAM&lt;/code&gt; authorization:&lt;/p&gt;


&lt;pre&gt;400: Invalid request&lt;br&gt;
&lt;/pre&gt; 

&lt;p&gt;Next, let’s consider how the above changes for a &lt;code&gt;PUT&lt;/code&gt; request. Note the addition to the request body as well as a content-type header.&lt;/p&gt;


&lt;pre&gt;400: Invalid request&lt;br&gt;
&lt;/pre&gt; 

&lt;p&gt;I hope you found the above useful as you work with these great frontend packages and Amazon API Gateway.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
