

# Amazon API Gateway REST API tutorials
<a name="api-gateway-rest-tutorials"></a>

The following tutorials provide hands-on exercises to help you learn about API Gateway REST APIs.

**Topics**
+ [

# Choose an AWS Lambda integration tutorial
](getting-started-with-lambda-integration.md)
+ [

# Tutorial: Create a REST API by importing an example
](api-gateway-create-api-from-example.md)
+ [

# Choose an HTTP integration tutorial
](getting-started-http-integrations.md)
+ [

# Tutorial: Create a REST API with a private integration
](getting-started-with-private-integration.md)
+ [

# Tutorial: Create a REST API with an AWS integration
](getting-started-aws-proxy.md)
+ [

# Tutorial: Create a calculator REST API with two AWS service integrations and one Lambda non-proxy integration
](integrating-api-with-aws-services-lambda.md)
+ [

# Tutorial: Create a REST API as an Amazon S3 proxy
](integrating-api-with-aws-services-s3.md)
+ [

# Tutorial: Create a REST API as an Amazon Kinesis proxy
](integrating-api-with-aws-services-kinesis.md)
+ [

# Tutorial: Create a REST API using AWS SDKs or the AWS CLI
](api-gateway-create-api-cli-sdk.md)
+ [

# Tutorial: Create a private REST API
](private-api-tutorial.md)

# Choose an AWS Lambda integration tutorial
<a name="getting-started-with-lambda-integration"></a>

 To build an API with Lambda integrations, you can use Lambda proxy integration or Lambda non-proxy integration. 

In Lambda proxy integration, the input to the Lambda function can be expressed as any combination of request headers, path variables, query string parameters, body, and API configuration data. You only need to choose a Lambda function. API Gateway configures the integration request and integration response for you. Once set up, your API method can evolve without modifying the existing settings. This is possible because the backend Lambda function parses the incoming request data and responds to the client.

In Lambda non-proxy integration, you must ensure that input to the Lambda function is supplied as the integration request payload. You must map any input data the client supplied as request parameters into the proper integration request body. You might also need to translate the client-supplied request body into a format recognized by the Lambda function. 

In either a Lambda proxy or a Lambda non-proxy integration, you can use a Lambda function in a different account from the account where you created your API.

**Topics**
+ [

# Tutorial: Create a REST API with a Lambda proxy integration
](api-gateway-create-api-as-simple-proxy-for-lambda.md)
+ [

# Tutorial: Create a REST API with a Lambda non-proxy integration
](getting-started-lambda-non-proxy-integration.md)
+ [

# Tutorial: Create a REST API with a cross-account Lambda proxy integration
](apigateway-cross-account-lambda-integrations.md)

# Tutorial: Create a REST API with a Lambda proxy integration
<a name="api-gateway-create-api-as-simple-proxy-for-lambda"></a>

[Lambda proxy integration](set-up-lambda-proxy-integrations.md) is a lightweight, flexible API Gateway API integration type that allows you to integrate an API method – or an entire API – with a Lambda function. The Lambda function can be written in [any language that Lambda supports](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html). Because it's a proxy integration, you can change the Lambda function implementation at any time without needing to redeploy your API.

In this tutorial, you do the following:
+ Create a "Hello, World\$1" Lambda function to be the backend for the API.
+ Create and test a "Hello, World\$1" API with Lambda proxy integration.

**Topics**
+ [

## Create a "Hello, World\$1" Lambda function
](#api-gateway-proxy-integration-create-lambda-backend)
+ [

## Create a "Hello, World\$1" API
](#api-gateway-create-api-as-simple-proxy-for-lambda-build)
+ [

## Deploy and test the API
](#api-gateway-create-api-as-simple-proxy-for-lambda-test)

## Create a "Hello, World\$1" Lambda function
<a name="api-gateway-proxy-integration-create-lambda-backend"></a>

**To create a "Hello, World\$1" Lambda function in the Lambda console**

1. Sign in to the Lambda console at [https://console.aws.amazon.com/lambda](https://console.aws.amazon.com/lambda).

1. On the AWS navigation bar, choose an [AWS Region](https://docs.aws.amazon.com/general/latest/gr/apigateway.html).
**Note**  
Note the region where you create the Lambda function. You'll need it when you create the API.

1. Choose **Functions** in the navigation pane.

1. Choose **Create function**.

1. Choose **Author from scratch**.

1. Under **Basic information**, do the following:

   1. In **Function name**, enter **GetStartedLambdaProxyIntegration**.

   1. For **Runtime**, choose either the latest supported **Node.js** or **Python** runtime.

   1. For **Architecture**, keep the default setting.

   1. Under **Permissions**, expand **Change default execution role**. For **Execution role** dropdown list, choose **Create new role from AWS policy templates**.

   1. In **Role name**, enter **GetStartedLambdaBasicExecutionRole**.

   1. Leave the **Policy templates** field blank.

   1. Choose **Create function**.

1. Under **Function code**, in the inline code editor, copy/paste the following code:

------
#### [ Node.js ]

   ```
   export const handler = async(event, context) => {
       console.log('Received event:', JSON.stringify(event, null, 2));
       var res ={
           "statusCode": 200,
           "headers": {
               "Content-Type": "*/*"
           }
       };
       var greeter = 'World';
       if (event.greeter && event.greeter!=="") {
           greeter =  event.greeter;
       } else if (event.body && event.body !== "") {
           var body = JSON.parse(event.body);
           if (body.greeter && body.greeter !== "") {
               greeter = body.greeter;
           }
       } else if (event.queryStringParameters && event.queryStringParameters.greeter && event.queryStringParameters.greeter !== "") {
           greeter = event.queryStringParameters.greeter;
       } else if (event.multiValueHeaders && event.multiValueHeaders.greeter && event.multiValueHeaders.greeter != "") {
           greeter = event.multiValueHeaders.greeter.join(" and ");
       } else if (event.headers && event.headers.greeter && event.headers.greeter != "") {
           greeter = event.headers.greeter;
       } 
       res.body = "Hello, " + greeter + "!";
       return res
   };
   ```

------
#### [ Python ]

   ```
   import json
   
   
   def lambda_handler(event, context):
       print(event)
   
       greeter = 'World'
   
       try:
           if (event['queryStringParameters']) and (event['queryStringParameters']['greeter']) and (
                   event['queryStringParameters']['greeter'] is not None):
               greeter = event['queryStringParameters']['greeter']
       except KeyError:
           print('No greeter')
   
       try:
           if (event['multiValueHeaders']) and (event['multiValueHeaders']['greeter']) and (
                   event['multiValueHeaders']['greeter'] is not None):
               greeter = " and ".join(event['multiValueHeaders']['greeter'])
       except KeyError:
           print('No greeter')
   
       try:
           if (event['headers']) and (event['headers']['greeter']) and (
                   event['headers']['greeter'] is not None):
               greeter = event['headers']['greeter']
       except KeyError:
           print('No greeter')
   
       if (event['body']) and (event['body'] is not None):
           body = json.loads(event['body'])
           try:
               if (body['greeter']) and (body['greeter'] is not None):
                   greeter = body['greeter']
           except KeyError:
               print('No greeter')
   
       res = {
           "statusCode": 200,
           "headers": {
               "Content-Type": "*/*"
           },
           "body": "Hello, " + greeter + "!"
       }
   
       return res
   ```

------

1. Choose **Deploy**.

## Create a "Hello, World\$1" API
<a name="api-gateway-create-api-as-simple-proxy-for-lambda-build"></a>

Now create an API for your "Hello, World\$1" Lambda function by using the API Gateway console.

**To create a "Hello, World\$1" API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. If this is your first time using API Gateway, you see a page that introduces you to the features of the service. Under **REST API**, choose **Build**. When the **Create Example API** popup appears, choose **OK**.

   If this is not your first time using API Gateway, choose **Create API**. Under **REST API**, choose **Build**.

1.  For **API name**, enter **LambdaProxyAPI**.

1. (Optional) For **Description**, enter a description.

1. Keep **API endpoint type** set to **Regional**.

1. For **IP address type**, select **IPv4**.

1. Choose **Create API**.

After you create an API, you create a resource. Typically, API resources are organized in a resource tree according to the application logic. For this example, you create a **/helloworld** resource. 

**To create a resource**

1. Choose **Create resource**.

1. Keep **Proxy resource** turned off. 

1. Keep **Resource path** as `/`.

1. For **Resource name**, enter **helloworld**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

 In a proxy integration, the entire request is sent to the backend Lambda function as-is, via a catch-all `ANY` method that represents any HTTP method. The actual HTTP method is specified by the client at run time. The `ANY` method allows you to use a single API method setup for all of the supported HTTP methods: `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, and `PUT`.

**To create an `ANY` method**

1. Select the **/helloworld** resource, and then choose **Create method**.

1. For **Method type**, select **ANY**.

1. For **Integration type**, select **Lambda function**.

1. Turn on **Lambda proxy integration**.

1. For **Lambda function**, select the AWS Region where you created your Lambda function, and then enter the function name.

1. To use the default timeout value of 29 seconds, keep **Default timeout** turned on. To set a custom timeout, choose **Default timeout** and enter a timeout value between `50` and `29000` milliseconds.

1. Choose **Create method**.

## Deploy and test the API
<a name="api-gateway-create-api-as-simple-proxy-for-lambda-test"></a>

**To deploy your API**

1. Choose **Deploy API**.

1. For **Stage**, select **New stage**.

1. For **Stage name**, enter **test**.

1. (Optional) For **Description**, enter a description.

1. Choose **Deploy**.

1. Under **Stage details**, choose the copy icon to copy your API's invoke URL.

### Use browser and cURL to test an API with Lambda proxy integration
<a name="api-gateway-create-api-as-simple-proxy-for-lambda-test-curl"></a>

You can use a browser or [cURL](https://curl.se/) to test your API.

To test `GET` requests using only query string parameters, you can enter the URL for the API's `helloworld` resource into a browser address bar. 

To create the URL for the API's `helloworld` resource, append the resource `helloworld` and the query string parameter `?greeter=John` to your invoke URL. Your URL should look like the following.

```
https://r275xc9bmd.execute-api.us-east-1.amazonaws.com/test/helloworld?greeter=John
```

For other methods, you must use more advanced REST API testing utilities, such as [POSTMAN](https://www.postman.com/) or [cURL](https://curl.se/). This tutorial uses cURL. The cURL command examples below assume that cURL is installed on your computer.

**To test your deployed API using cURL:**

1. Open a terminal window.

1. Copy the following cURL command and paste it into the terminal window, and replace the invoke URL with the one you copied in the previous step and add **/helloworld** to the end of the URL.
**Note**  
If you're running the command on Windows, use this syntax instead:  

   ```
   curl -v -X POST "https://r275xc9bmd.execute-api.us-east-1.amazonaws.com/test/helloworld" -H "content-type: application/json" -d "{ \"greeter\": \"John\" }"
   ```

   1. To call the API with the query string parameter of `?greeter=John`:

      ```
      curl -X GET 'https://r275xc9bmd.execute-api.us-east-1.amazonaws.com/test/helloworld?greeter=John'
      ```

   1. To call the API with a header parameter of `greeter:John`:

      ```
      curl -X GET https://r275xc9bmd.execute-api.us-east-1.amazonaws.com/test/helloworld \
        -H 'content-type: application/json' \
        -H 'greeter: John'
      ```

   1. To call the API with a body of `{"greeter":"John"}`:

      ```
      curl -X POST https://r275xc9bmd.execute-api.us-east-1.amazonaws.com/test/helloworld \
        -H 'content-type: application/json' \
        -d '{ "greeter": "John" }'
      ```

   In all the cases, the output is a 200 response with the following response body:

   ```
   Hello, John!
   ```

# Tutorial: Create a REST API with a Lambda non-proxy integration
<a name="getting-started-lambda-non-proxy-integration"></a>

In this walkthrough, we use the API Gateway console to build an API that enables a client to call Lambda functions through the Lambda non-proxy integration (also known as custom integration). For more information about AWS Lambda and Lambda functions, see the [AWS Lambda Developer Guide](https://docs.aws.amazon.com/lambda/latest/dg/). 

To facilitate learning, we chose a simple Lambda function with minimal API setup to walk you through the steps of building an API Gateway API with the Lambda custom integration. When necessary, we describe some of the logic. For a more detailed example of the Lambda custom integration, see [Tutorial: Create a calculator REST API with two AWS service integrations and one Lambda non-proxy integration](integrating-api-with-aws-services-lambda.md). 

Before creating the API, set up the Lambda backend by creating a Lambda function in AWS Lambda, described next.

**Topics**
+ [

## Create a Lambda function for Lambda non-proxy integration
](#getting-started-new-lambda)
+ [

## Create an API with Lambda non-proxy integration
](#getting-started-new-api)
+ [

## Test invoking the API method
](#getting-started-new-get)
+ [

## Deploy the API
](#getting-started-deploy-api)
+ [

## Test the API in a deployment stage
](#getting-started-test)
+ [

## Clean up
](#getting-started-clean-up)

## Create a Lambda function for Lambda non-proxy integration
<a name="getting-started-new-lambda"></a>

**Note**  
Creating Lambda functions may result in charges to your AWS account.

 In this step, you create a "Hello, World\$1"-like Lambda function for the Lambda custom integration. Throughout this walkthrough, the function is called `GetStartedLambdaIntegration`.

 The implementation of this `GetStartedLambdaIntegration` Lambda function is as follows: 

------
#### [ Node.js ]

```
'use strict';
var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];            
var times = ['morning', 'afternoon', 'evening', 'night', 'day'];

export const handler = async(event) => {
  console.log(event);
  // Parse the input for the name, city, time and day property values
  let name = event.name === null || event.name === undefined || event.name === "" ? 'you' : event.name;
  let city = event.city === undefined ? 'World' : event.city;
  let time = times.indexOf(event.time)<0 ? 'day' : event.time;
  let day = days.indexOf(event.day)<0 ? null : event.day;

  // Generate a greeting
  let greeting = 'Good ' + time + ', ' + name + ' of ' + city + '. ';
  if (day) greeting += 'Happy ' + day + '!';
  
  // Log the greeting to CloudWatch
  console.log('Hello: ', greeting);
  
  // Return a greeting to the caller
  return {"greeting": greeting}
};
```

------
#### [ Python ]

```
import json

days = {
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday'}
times = {'morning', 'afternoon', 'evening', 'night', 'day'}


def lambda_handler(event, context):
    print(event)
    # parse the input for the name, city, time, and day property values
    name = event.get("name") or 'you'
    city = event.get("city") or 'World'
    try:
        if event['time'] in times:
            time = event['time']
        else:
            time = 'day'
    except KeyError:
        time = 'day'
    try:
        if event['day'] in days:
            day = event['day']
        else:
            day = ''
    except KeyError:
        day = ''
    # Generate a greeting
    greeting = 'Good ' + time + ', ' + name + ' of ' + \
        city + '.' + ['', ' Happy ' + day + '!'][day != '']
    # Log the greeting to CloudWatch
    print(greeting)

    # Return a greeting to the caller
    return {"greeting": greeting}
```

------

For the Lambda custom integration, API Gateway passes the input to the Lambda function from the client as the integration request body. The `event` object of the Lambda function handler is the input. 

Our Lambda function is simple. It parses the input `event` object for the `name`, `city`, `time`, and `day` properties. It then returns a greeting, as a JSON object of `{"message":greeting}`, to the caller. The message is in the `"Good [morning|afternoon|day], [name|you] in [city|World]. Happy day!"` pattern. It is assumed that the input to the Lambda function is of the following JSON object: 

```
{
  "city": "...",
  "time": "...",
  "day": "...",
  "name" : "..."
}
```

For more information, see the [AWS Lambda Developer Guide](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html). 

In addition, the function logs its execution to Amazon CloudWatch by calling `console.log(...)`. This is helpful for tracing calls when debugging the function. To allow the `GetStartedLambdaIntegration` function to log the call, set an IAM role with appropriate policies for the Lambda function to create the CloudWatch streams and add log entries to the streams. The Lambda console guides you through to create the required IAM roles and policies.

If you set up the API without using the API Gateway console, such as when [importing an API from an OpenAPI file](https://github.com/aws-samples/api-gateway-secure-pet-store/blob/master/src/main/resources/swagger.yaml#L39), you must explicitly create, if necessary, and set up an invocation role and policy for API Gateway to invoke the Lambda functions. For more information on how to set up Lambda invocation and execution roles for an API Gateway API, see [Control access to a REST API with IAM permissions](permissions.md). 

 Compared to `GetStartedLambdaProxyIntegration`, the Lambda function for the Lambda proxy integration, the `GetStartedLambdaIntegration` Lambda function for the Lambda custom integration only takes input from the API Gateway API integration request body. The function can return an output of any JSON object, a string, a number, a Boolean, or even a binary blob. The Lambda function for the Lambda proxy integration, in contrast, can take the input from any request data, but must return an output of a particular JSON object. The `GetStartedLambdaIntegration` function for the Lambda custom integration can have the API request parameters as input, provided that API Gateway maps the required API request parameters to the integration request body before forwarding the client request to the backend. For this to happen, the API developer must create a mapping template and configure it on the API method when creating the API. 

Now, create the `GetStartedLambdaIntegration` Lambda function. 

**To create the `GetStartedLambdaIntegration` Lambda function for Lambda custom integration**

1. Open the AWS Lambda console at [https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/).

1. Do one of the following:
   + If the welcome page appears, choose **Get Started Now** and then choose **Create function**.
   + If the **Lambda > Functions** list page appears, choose **Create function**.

1. Choose **Author from scratch**. 

1. In the **Author from scratch** pane, do the following:

   1. For **Name**, enter **GetStartedLambdaIntegration** as the Lambda function name.

   1. For **Runtime**, choose either the latest supported **Node.js** or **Python** runtime.

   1. For **Architecture**, keep the default setting.

   1. Under **Permissions**, expand **Change default execution role**. For **Execution role** dropdown list, choose **Create new role from AWS policy templates**.

   1. For **Role name**, enter a name for your role (for example, **GetStartedLambdaIntegrationRole**).

   1. For **Policy templates**, choose **Simple microservice permissions**.

   1. Choose **Create function**.

1. In the **Configure function** pane, under **Function code** do the following:

   1. Copy the Lambda function code listed in the beginning of this section and paste it in the inline code editor.

   1. Leave the default choices for all other fields in this section.

   1. Choose **Deploy**.

1. To test the newly created function, choose the **Test** tab.

   1. For **Event name**, enter **HelloWorldTest**. 

   1. For **Event JSON**, replace the default code with the following.

      ```
      {
        "name": "Jonny",
        "city": "Seattle",
        "time": "morning",
        "day": "Wednesday"
      }
      ```

   1.  Choose **Test** to invoke the function. The **Execution result: succeeded** section is shown. Expand **Details** and you see the following output.

      ```
      {
          "greeting": "Good morning, Jonny of Seattle. Happy Wednesday!"
      }
      ```

      The output is also written to CloudWatch Logs. 

 As a side exercise, you can use the IAM console to view the IAM role (`GetStartedLambdaIntegrationRole`) that was created as part of the Lambda function creation. Attached to this IAM role are two inline policies. One stipulates the most basic permissions for Lambda execution. It permits calling the CloudWatch `CreateLogGroup` for any CloudWatch resources of your account in the region where the Lambda function is created. This policy also allows creating the CloudWatch streams and logging events for the `GetStartedLambdaIntegration` Lambda function. 

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:us-east-1:111111111111:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:111111111111:log-group:/aws/lambda/GetStartedLambdaIntegration:*"
            ]
        }
    ]
}
```

------

The other policy document applies to invoking another AWS service that is not used in this example. You can skip it for now. 

 Associated with the IAM role is a trusted entity, which is `lambda.amazonaws.com`. Here is the trust relationship: 

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

------

 The combination of this trust relationship and the inline policy makes it possible for the Lambda function to invoke a `console.log()` function to log events to CloudWatch Logs. 

## Create an API with Lambda non-proxy integration
<a name="getting-started-new-api"></a>

 With the Lambda function (`GetStartedLambdaIntegration`) created and tested, you are ready to expose the function through an API Gateway API. For illustration purposes, we expose the Lambda function with a generic HTTP method. We use the request body, a URL path variable, a query string, and a header to receive required input data from the client. We turn on the API Gateway request validator for the API to ensure that all of the required data is properly defined and specified. We configure a mapping template for API Gateway to transform the client-supplied request data into the valid format as required by the backend Lambda function.

**To create an API with a Lambda non-proxy integration**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. If this is your first time using API Gateway, you see a page that introduces you to the features of the service. Under **REST API**, choose **Build**. When the **Create Example API** popup appears, choose **OK**.

   If this is not your first time using API Gateway, choose **Create API**. Under **REST API**, choose **Build**.

1.  For **API name**, enter **LambdaNonProxyAPI**.

1. (Optional) For **Description**, enter a description.

1. Keep **API endpoint type** set to **Regional**.

1. For **IP address type**, select **IPv4**.

1. Choose **Create API**.

After creating your API, you create a **/\$1city\$1** resource. This is an example of a resource with a path variable that takes an input from the client. Later, you map this path variable into the Lambda function input using a mapping template.

**To create a resource**

1. Choose **Create resource**.

1. Keep **Proxy resource** turned off. 

1. Keep **Resource path** as `/`.

1. For **Resource name**, enter **\$1city\$1**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

After creating your **/\$1city\$1** resource, you create an `ANY` method. The `ANY` HTTP verb is a placeholder for a valid HTTP method that a client submits at run time. This example shows that `ANY` method can be used for Lambda custom integration as well as for Lambda proxy integration.

**To create an `ANY` method**

1. Select the **/\$1city\$1** resource, and then choose **Create method**.

1. For **Method type**, select **ANY**.

1. For **Integration type**, select **Lambda function**.

1. Keep **Lambda proxy integration** turned off.

1. For **Lambda function**, select the AWS Region where you created your Lambda function, and then enter the function name.

1. Choose **Method request settings.**

   Now, you turn on a request validator for a URL path variable, a query string parameter, and a header to ensure that all of the required data is defined. For this example, you create a `time` query string parameter and a `day` header. 

1. For **Request validator**, select **Validate query string parameters and headers**.

1. Choose **URL query string parameters** and do the following: 

   1. Choose **Add query string**.

   1. For **Name**, enter **time**.

   1. Turn on **Required**.

   1. Keep **Caching** turned off. 

1. Choose **HTTP request headers** and do the following: 

   1. Choose **Add header**.

   1. For **Name**, enter **day**.

   1. Turn on **Required**.

   1. Keep **Caching** turned off. 

1. Choose **Create method**.

After turning on a request validator, you configure the integration request for the `ANY` method by adding a body-mapping template to transform the incoming request into a JSON payload, as required by the backend Lambda function. 

**To configure the integration request**

1. On the **Integration request** tab, under the **Integration request settings**, choose **Edit**.

1. For **Request body passthrough**, select **When there are no templates defined (recommended)**.

1. Choose **Mapping templates**.

1. Choose **Add mapping template**.

1. For **Content type**, enter **application/json**.

1. For **Template body**, enter the following code:

   ```
   #set($inputRoot = $input.path('$'))
   {
     "city": "$input.params('city')",
     "time": "$input.params('time')",
     "day":  "$input.params('day')",
     "name": "$inputRoot.callerName"
   }
   ```

1. Choose **Save**.

## Test invoking the API method
<a name="getting-started-new-get"></a>

 The API Gateway console provides a testing facility for you to test invoking the API before it is deployed. You use the Test feature of the console to test the API by submitting the following request: 

```
POST /Seattle?time=morning
day:Wednesday

{
    "callerName": "John"
}
```

 In this test request, you'll set `ANY` to `POST`, set `{city}` to `Seattle`, assign `Wednesday` as the `day` header value, and assign `"John"` as the `callerName` value. 

**To test the `ANY` method**

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. For **Method type**, select `POST`.

1. For **Path**, under **city**, enter **Seattle**.

1. For **Query strings**, enter **time=morning**.

1. For **Headers**, enter **day:Wednesday**.

1. For **Request Body**, enter **\$1 "callerName": "John" \$1**.

1. Choose **Test**.

Verify that the returned response payload is as follows:

```
{
  "greeting": "Good morning, John of Seattle. Happy Wednesday!"
}
```

You can also view the logs to examine how API Gateway processes the request and response.

```
Execution log for request test-request
Thu Aug 31 01:07:25 UTC 2017 : Starting execution for request: test-invoke-request
Thu Aug 31 01:07:25 UTC 2017 : HTTP Method: POST, Resource Path: /Seattle
Thu Aug 31 01:07:25 UTC 2017 : Method request path: {city=Seattle}
Thu Aug 31 01:07:25 UTC 2017 : Method request query string: {time=morning}
Thu Aug 31 01:07:25 UTC 2017 : Method request headers: {day=Wednesday}
Thu Aug 31 01:07:25 UTC 2017 : Method request body before transformations: { "callerName": "John" }
Thu Aug 31 01:07:25 UTC 2017 : Request validation succeeded for content type application/json
Thu Aug 31 01:07:25 UTC 2017 : Endpoint request URI: https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:GetStartedLambdaIntegration/invocations
Thu Aug 31 01:07:25 UTC 2017 : Endpoint request headers: {x-amzn-lambda-integration-tag=test-request, Authorization=****************************************************************************************************************************************************************************************************************************************************************************************************************************************338c72, X-Amz-Date=20170831T010725Z, x-amzn-apigateway-api-id=beags1mnid, X-Amz-Source-Arn=arn:aws:execute-api:us-west-2:123456789012:beags1mnid/null/POST/{city}, Accept=application/json, User-Agent=AmazonAPIGateway_beags1mnid, X-Amz-Security-Token=FQoDYXdzELL//////////wEaDMHGzEdEOT/VvGhabiK3AzgKrJw+3zLqJZG4PhOq12K6W21+QotY2rrZyOzqhLoiuRg3CAYNQ2eqgL5D54+63ey9bIdtwHGoyBdq8ecWxJK/YUnT2Rau0L9HCG5p7FC05h3IvwlFfvcidQNXeYvsKJTLXI05/yEnY3ttIAnpNYLOezD9Es8rBfyruHfJfOqextKlsC8DymCcqlGkig8qLKcZ0hWJWVwiPJiFgL7laabXs++ZhCa4hdZo4iqlG729DE4gaV1mJVdoAagIUwLMo+y4NxFDu0r7I0/EO5nYcCrppGVVBYiGk7H4T6sXuhTkbNNqVmXtV3ch5bOlh7 [TRUNCATED]
Thu Aug 31 01:07:25 UTC 2017 : Endpoint request body after transformations: {
  "city": "Seattle",
  "time": "morning",
  "day": "Wednesday",
  "name" : "John"
}
Thu Aug 31 01:07:25 UTC 2017 : Sending request to https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:GetStartedLambdaIntegration/invocations
Thu Aug 31 01:07:25 UTC 2017 : Received response. Integration latency: 328 ms
Thu Aug 31 01:07:25 UTC 2017 : Endpoint response body before transformations: {"greeting":"Good morning, John of Seattle. Happy Wednesday!"}
Thu Aug 31 01:07:25 UTC 2017 : Endpoint response headers: {x-amzn-Remapped-Content-Length=0, x-amzn-RequestId=c0475a28-8de8-11e7-8d3f-4183da788f0f, Connection=keep-alive, Content-Length=62, Date=Thu, 31 Aug 2017 01:07:25 GMT, X-Amzn-Trace-Id=root=1-59a7614d-373151b01b0713127e646635;sampled=0, Content-Type=application/json}
Thu Aug 31 01:07:25 UTC 2017 : Method response body after transformations: {"greeting":"Good morning, John of Seattle. Happy Wednesday!"}
Thu Aug 31 01:07:25 UTC 2017 : Method response headers: {X-Amzn-Trace-Id=sampled=0;root=1-59a7614d-373151b01b0713127e646635, Content-Type=application/json}
Thu Aug 31 01:07:25 UTC 2017 : Successfully completed execution
Thu Aug 31 01:07:25 UTC 2017 : Method completed with status: 200
```

The logs show the incoming request before the mapping and the integration request after the mapping. When a test fails, the logs are useful for evaluating whether the original input is correct or the mapping template works correctly. 

## Deploy the API
<a name="getting-started-deploy-api"></a>

 The test invocation is a simulation and has limitations. For example, it bypasses any authorization mechanism enacted on the API. To test the API execution in real time, you must deploy the API first. To deploy an API, you create a stage to create a snapshot of the API at that time. The stage name also defines the base path after the API's default host name. The API's root resource is appended after the stage name. When you modify the API, you must redeploy it to a new or existing stage before the changes take effect. 

**To deploy the API to a stage**

1. Choose **Deploy API**.

1. For **Stage**, select **New stage**.

1. For **Stage name**, enter **test**.
**Note**  
The input must be UTF-8 encoded (i.e., unlocalized) text.

1. (Optional) For **Description**, enter a description.

1. Choose **Deploy**.

Under **Stage details**, choose the copy icon to copy your API's invoke URL. The general pattern of the API's base URL is `https://api-id.region.amazonaws.com/stageName`. For example, the base URL of the API (`beags1mnid`) created in the `us-west-2` region and deployed to the `test` stage is `https://beags1mnid.execute-api.us-west-2.amazonaws.com/test`.

## Test the API in a deployment stage
<a name="getting-started-test"></a>

There are several ways you can test a deployed API. For GET requests using only URL path variables or query string parameters, you can enter the API resource URL in a browser. For other methods, you must use more advanced REST API testing utilities, such as [POSTMAN](https://www.postman.com/) or [cURL](https://curl.se/).

**To test the API using cURL**

1. Open a terminal window on your local computer connected to the internet.

1. To test `POST /Seattle?time=evening`:

   Copy the following cURL command and paste it into the terminal window.

   ```
   curl -v -X POST \
     'https://beags1mnid.execute-api.us-west-2.amazonaws.com/test/Seattle?time=evening' \
     -H 'content-type: application/json' \
     -H 'day: Thursday' \
     -H 'x-amz-docs-region: us-west-2' \
     -d '{
   	"callerName": "John"
   }'
   ```

   You should get a successful response with the following payload:

   ```
   {"greeting":"Good evening, John of Seattle. Happy Thursday!"}
   ```

   If you change `POST` to `PUT` in this method request, you get the same response.

## Clean up
<a name="getting-started-clean-up"></a>

If you no longer need the Lambda functions you created for this walkthrough, you can delete them now. You can also delete the accompanying IAM resources.

**Warning**  
If you plan to complete the other walkthroughs in this series, do not delete the Lambda execution role or the Lambda invocation role. If you delete a Lambda function that your APIs rely on, those APIs will no longer work. Deleting a Lambda function cannot be undone. If you want to use the Lambda function again, you must re-create the function.  
If you delete an IAM resource that a Lambda function relies on, that Lambda function will no longer work, and any APIs that rely on that function will no longer work. Deleting an IAM resource cannot be undone. If you want to use the IAM resource again, you must re-create the resource. 

**To delete the Lambda function**

1. Sign in to the AWS Management Console and open the AWS Lambda console at [https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/).

1. From the list of functions, choose **GetStartedLambdaIntegration**, choose **Actions**, and then choose **Delete function**. When prompted, choose **Delete** again.

**To delete the associated IAM resources**

1. Open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. From **Details**, choose **Roles**.

1. From the list of roles, choose **GetStartedLambdaIntegrationRole**, choose **Role Actions**, and then choose **Delete Role**. Follow the steps in the console to delete the role.

# Tutorial: Create a REST API with a cross-account Lambda proxy integration
<a name="apigateway-cross-account-lambda-integrations"></a>

You can now use an AWS Lambda function from a different AWS account as your API integration backend. Each account can be in any region where Amazon API Gateway is available. This makes it easy to centrally manage and share Lambda backend functions across multiple APIs.

In this section, we show how to configure cross-account Lambda proxy integration using the Amazon API Gateway console.

## Create API for API Gateway cross-account Lambda integration
<a name="apigateway-cross-account-lambda-integrations-create-api"></a>

**To create an API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. If this is your first time using API Gateway, you see a page that introduces you to the features of the service. Under **REST API**, choose **Build**. When the **Create Example API** popup appears, choose **OK**.

   If this is not your first time using API Gateway, choose **Create API**. Under **REST API**, choose **Build**.

1.  For **API name**, enter **CrossAccountLambdaAPI**.

1. (Optional) For **Description**, enter a description.

1. Keep **API endpoint type** set to **Regional**.

1. For **IP address type**, select **IPv4**.

1. Choose **Create API**.

## Create Lambda integration function in another account
<a name="apigateway-cross-account-lambda-integrations-create-lambda-function"></a>

Now you'll create a Lambda function in a different account from the one in which you created the example API.

**Creating a Lambda function in another account**

1. Log in to the Lambda console in a different account from the one where you created your API Gateway API.

1. Choose **Create function**.

1. Choose **Author from scratch**.

1. Under **Author from scratch**, do the following:

   1. For **Function name**, enter a name.

   1. From the **Runtime** drop-down list, choose a supported Node.js runtime.

   1. For **Architecture**, keep the default setting.

   1. Under **Permissions**, expand **Choose or create an execution role**. You can create a role or choose an existing role.

   1. Choose **Create function** to continue.

1. Scroll down to the **Function code** pane.

1. Enter the Node.js function implementation from [Tutorial: Create a REST API with a Lambda proxy integration](api-gateway-create-api-as-simple-proxy-for-lambda.md).

1. Choose **Deploy**.

1. Note the full ARN for your function (in the upper right corner of the Lambda function pane). You'll need it when you create your cross-account Lambda integration.

## Configure cross-account Lambda integration
<a name="apigateway-cross-account-lambda-integrations-create-integration2"></a>

Once you have a Lambda integration function in a different account, you can use the API Gateway console to add it to your API in your first account.

**Note**  
If you are configuring a cross-region, cross-account authorizer, the `sourceArn` that is added to the target function should use the region of the function, not the region of the API.

After you create an API, you create a resource. Typically, API resources are organized in a resource tree according to the application logic. For this example, you create a **/helloworld** resource. 

**To create a resource**

1. Choose **Create resource**.

1. Keep **Proxy resource** turned off. 

1. Keep **Resource path** as `/`.

1. For **Resource name**, enter **helloworld**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

After you create an resource, you create a `GET` method. You integrate the `GET` method with a Lambda function in another account. 

**To create a `GET` method**

1. Select the **/helloworld** resource, and then choose **Create method**.

1. For **Method type**, select **GET**.

1. For **Integration type**, select **Lambda function**.

1. Turn on **Lambda proxy integration**.

1. For **Lambda function**, enter the full ARN of your Lambda function from Step 1. 

   In the Lambda console, you can find the ARN for your function in the upper right corner of the console window.

1. When you enter the ARN, a `aws lambda add-permission` command string will appear. This policy grants your first account access to your second account's Lambda function. Copy and paste the `aws lambda add-permission` command string into an AWS CLI window that is configured for your second account.

1. Choose **Create method**.

You can see your updated policy for your function in the Lambda console.

**(Optional) To see your updated policy**

1. Sign in to the AWS Management Console and open the AWS Lambda console at [https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/).

1. Choose your Lambda function.

1. Choose **Permissions**.

   You should see an `Allow` policy with a `Condition` clause in which the in the `AWS:SourceArn` is the ARN for your API's `GET` method.

# Tutorial: Create a REST API by importing an example
<a name="api-gateway-create-api-from-example"></a>

You can use the Amazon API Gateway console to create and test a simple REST API with the HTTP integration for a PetStore website. The API definition is preconfigured as a OpenAPI 2.0 file. After loading the API definition into API Gateway, you can use the API Gateway console to examine the API's basic structure or simply deploy and test the API. 

 The PetStore example API supports the following methods for a client to access the HTTP backend website of `http://petstore-demo-endpoint.execute-api.com/petstore/pets`. 

**Note**  
This tutorial uses an HTTP endpoint as an example. When you create your own APIs, we recommend you use HTTPS endpoints for your HTTP integrations.
+ `GET /`: for read access of the API's root resource that is not integrated with any backend endpoint. API Gateway responds with an overview of the PetStore website. This is an example of the `MOCK` integration type.
+ `GET /pets`: for read access to the API's `/pets` resource that is integrated with the like-named backend `/pets` resource. The backend returns a page of available pets in the PetStore. This is an example of the `HTTP` integration type. The URL of the integration endpoint is `http://petstore-demo-endpoint.execute-api.com/petstore/pets`.
+ `POST /pets`: for write access to the API's `/pets` resource that is integrated with the backend `/petstore/pets` resource. Upon receiving a correct request, the backend adds the specified pet to the PetStore and returns the result to the caller. The integration is also `HTTP`.
+ `GET /pets/{petId}`: for read access to a pet as identified by a `petId` value as specified as a path variable of the incoming request URL. This method also has the `HTTP` integration type. The backend returns the specified pet found in the PetStore. The URL of the backend HTTP endpoint is `http://petstore-demo-endpoint.execute-api.com/petstore/pets/n`, where `n` is an integer as the identifier of the queried pet.

 The API supports CORS access via the `OPTIONS` methods of the `MOCK` integration type. API Gateway returns the required headers supporting CORS access. 

The following procedure walks you through the steps to create and test an API from an example using the API Gateway Console.

**To import, build, and test the example API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Do one of the following:
   + To create your first API, for **REST API**, choose **Build**.
   + If you've created an API before, choose **Create API**, and then choose **Build** for **REST API**.

1.  Under **Create REST API**, choose **Example API** and then choose **Create API** to create the example API. 

      
![\[Example REST API in the API Gateway console.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-new-console.png)

    You can scroll down the OpenAPI definition for details of this example API before choosing **Create API**. 

1. In the main navigation pane, choose **Resources**. The newly created API is shown as follows:

      
![\[The example API after importing it into the API Gateway console.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-result-new-console.png)

    The **Resources** pane shows the structure of the created API as a tree of nodes. API methods defined on each resource are edges of the tree. When a resource is selected, all of its methods are listed in the **Methods** table on the right. Displayed with each method is the method type, integration type, authorization type, and API key requirement. 

1.  To view the details of a method, to modify its set-up, or to test the method invocation, choose the method name from either the method list or the resource tree. Here, we choose the `POST /pets` method as an illustration: 

      
![\[The POST /pets method for the example API in the API Gateway console.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-post-method-execution-new-console.png)

    The resulting **Method execution** pane presents a logical view of the chosen (`POST /pets`) method's structure and behaviors.

   The **Method request** and **Method response** represent the API's interface with the frontend, and the **Integration request** and **Integration response** represent the API's interface with the backend.

    A client uses the API to access a backend feature through the **Method request**. API Gateway translates the client request, if necessary, into the form acceptable to the backend in **Integration request** before forwarding the incoming request to the backend. The transformed request is known as the integration request. Similarly, the backend returns the response to API Gateway in **Integration response**. API Gateway then routes it to **Method Response** before sending it to the client. Again, if necessary, API Gateway can map the backend response data to a form expected by the client. 

    For the `POST` method on an API resource, the method request payload can be passed through to the integration request without modification, if the method request's payload is of the same format as the integration request's payload. 

   The `GET /` method request uses the `MOCK` integration type and is not tied to any real backend endpoint. The corresponding **Integration response** is set up to return a static HTML page. When the method is called, the API Gateway simply accepts the request and immediately returns the configured integration response to the client by way of **Method response**. You can use the mock integration to test an API without requiring a backend endpoint. You can also use it to serve a local response, generated from a response body-mapping template. 

   As an API developer, you control the behaviors of your API's frontend interactions by configuring the method request and a method response. You control the behaviors of your API's backend interactions by setting up the integration request and integration response. These involve data mappings between a method and its corresponding integration. For now, we focus on testing the API to provide an end-to-end user experience. 

1.  Select the **Test** tab. You might need to choose the right arrow button to show the tab. 

1.  For example, to test the `POST /pets` method, enter the following **\$1"type": "dog","price": 249.99\$1** payload into the **Request body**, and then choose **Test**.

      
![\[Test the POST method in the API Gateway console.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-post-method-test-new-console.png)

    The input specifies the attributes of the pet that we want to add to the list of pets on the PetStore website. 

1. The results display as follows:

      
![\[The result of testing the POST method in the API Gateway console.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-post-method-test-result-new-console.png)

    The **Log** entry of the output shows the state changes from the method request to the integration request, and from the integration response to the method response. This can be useful for troubleshooting any mapping errors that cause the request to fail. In this example, no mapping is applied: the method request payload is passed through the integration request to the backend and, similarly, the backend response is passed through the integration response to the method response. 

    To test the API using a client other than the API Gateway test-invoke-request feature, you must first deploy the API to a stage. 

1.  To deploy the sample API, choose **Deploy API**. 

      
![\[Use the deploy button to deploy your API, so API callers can invoke your API.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-deploy-api-new-console.png)

1. For **Stage**, select **New stage**, and then enter **test**.

1. (Optional) For **Description**, enter a description.

1. Choose **Deploy**.

1.  In the resulting **Stages** pane, under **Stage details**, the **Invoke URL** displays the URL to invoke the API's `GET /` method request.   
![\[After you create your REST API, the console shows your API's invoke URL.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/getting-started-rest-invoke-url.png)

1. Choose the copy icon to copy your API's invoke URL, and then enter your API's invoke URL in a web browser. A successful response return the result, generated from the mapping template in the integration response. 

1.  In the **Stages** navigation pane, expand the **test** stage, select **GET** on `/pets/{petId}`, and then copy the **Invoke URL** value of `https://api-id.execute-api.region.amazonaws.com/test/pets/{petId}`. `{petId}` stands for a path variable. 

    Paste the **Invoke URL** value (obtained in the previous step) into the address bar of a browser, replacing `{petId}` by, for example, `1`, and press Enter to submit the request. A 200 OK response should return with the following JSON payload: 

   ```
   {
     "id": 1,
     "type": "dog",
     "price": 249.99
   }
   ```

    Invoking the API method as shown is possible because its **Authorization** type is set to `NONE`. If the `AWS_IAM` authorization were used, you would sign the request using the [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html) (SigV4) or [Signature Version 4a](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html#how-sigv4a-works) (SigV4a) protocols. For an example of such a request, see [Tutorial: Create a REST API with an HTTP non-proxy integration](api-gateway-create-api-step-by-step.md). 

# Choose an HTTP integration tutorial
<a name="getting-started-http-integrations"></a>

 To build an API with HTTP integration, you can use either an HTTP proxy integration or an HTTP custom integration.

In an HTTP proxy integration, you only need to set the HTTP method and the HTTP endpoint URI, according to the backend requirements. We recommend that you use the HTTP proxy integration, whenever possible, to take advantage of the streamlined API set up.

You might want to use an HTTP custom integration if you need to transform client request data for the backend or transform the backend response data for the client. 

**Topics**
+ [

# Tutorial: Create a REST API with an HTTP proxy integration
](api-gateway-create-api-as-simple-proxy-for-http.md)
+ [

# Tutorial: Create a REST API with an HTTP non-proxy integration
](api-gateway-create-api-step-by-step.md)

# Tutorial: Create a REST API with an HTTP proxy integration
<a name="api-gateway-create-api-as-simple-proxy-for-http"></a>

HTTP proxy integration is a simple, powerful, and versatile mechanism to build an API that allows a web application to access multiple resources or features of the integrated HTTP endpoint, for example the entire website, with a streamlined setup of a single API method. In HTTP proxy integration, API Gateway passes the client-submitted method request to the backend. The request data that is passed through includes the request headers, query string parameters, URL path variables, and payload. The backend HTTP endpoint or the web server parses the incoming request data to determine the response that it returns. HTTP proxy integration makes the client and backend interact directly with no intervention from API Gateway after the API method is set up, except for known issues such as unsupported characters, which are listed in [Amazon API Gateway important notes](api-gateway-known-issues.md).

With the all-encompassing proxy resource `{proxy+}`, and the catch-all `ANY` verb for the HTTP method, you can use an HTTP proxy integration to create an API of a single API method. The method exposes the entire set of the publicly accessible HTTP resources and operations of a website. When the backend web server opens more resources for public access, the client can use these new resources with the same API setup. To enable this, the website developer must communicate clearly to the client developer what the new resources are and what operations are applicable for each of them.



As a quick introduction, the following tutorial demonstrates the HTTP proxy integration. In the tutorial, we create an API using the API Gateway console to integrate with the PetStore website through a generic proxy resource `{proxy+}`, and create the HTTP method placeholder of `ANY`. 

**Topics**
+ [

## Create an API with HTTP proxy integration using the API Gateway console
](#api-gateway-create-api-as-simple-proxy-for-http-build)
+ [

## Test an API with HTTP proxy integration
](#api-gateway-create-api-as-simple-proxy-for-http-test)

## Create an API with HTTP proxy integration using the API Gateway console
<a name="api-gateway-create-api-as-simple-proxy-for-http-build"></a>

 The following procedure walks you through the steps to create and test an API with a proxy resource for an HTTP backend using the API Gateway console. The HTTP backend is the `PetStore` website (`http://petstore-demo-endpoint.execute-api.com/petstore/pets`) from [Tutorial: Create a REST API with an HTTP non-proxy integration](api-gateway-create-api-step-by-step.md), in which screenshots are used as visual aids to illustrate the API Gateway UI elements. If you are new to using the API Gateway console to create an API, you may want to follow that section first. 

**To create an API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. If this is your first time using API Gateway, you see a page that introduces you to the features of the service. Under **REST API**, choose **Build**. When the **Create Example API** popup appears, choose **OK**.

   If this is not your first time using API Gateway, choose **Create API**. Under **REST API**, choose **Build**.

1.  For **API name**, enter **HTTPProxyAPI**.

1. (Optional) For **Description**, enter a description.

1. Keep **API endpoint type** set to **Regional**.

1. For **IP address type**, select **IPv4**.

1. Choose **Create API**.

In this step, you create a proxy resource path of `{proxy+}`. This is the placeholder of any of the backend endpoints under `http://petstore-demo-endpoint.execute-api.com/`. For example, it can be `petstore`, `petstore/pets`, and `petstore/pets/{petId}`. API Gateway creates the `ANY` method when you create the `{proxy+}` resource and serves as a placeholder for any of the supported HTTP verbs at run time.

**To create a **/\$1proxy\$1\$1** resource**

1. Choose your API. 

1. In the main navigation pane, choose **Resources**.

1. Choose **Create resource**.

1. Turn on **Proxy resource**.

1. Keep **Resource path** as `/`.

1. For **Resource name**, enter **\$1proxy\$1\$1**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.  
![\[Create a child resource.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/api-gateway-simple-proxy-create-proxy-resource-new-console.png)

In this step, you integrate the `ANY` method with a backend HTTP endpoint, using a proxy integration. In a proxy integration, API Gateway passes the client-submitted method request to the backend with no intervention from API Gateway.

**To create an `ANY` method**

1. Choose the **/\$1proxy\$1\$1** resource.

1. Choose the **ANY** method.

1. Under the warning symbol, choose **Edit integration**. You cannot deploy an API that has a method without an integration.

1. For **Integration type**, select **HTTP**.

1. Turn on **HTTP proxy integration**.

1. For **HTTP method**, select **ANY**.

1. For **Endpoint URL**, enter **http://petstore-demo-endpoint.execute-api.com/\$1proxy\$1**.

1. Choose **Save**.

## Test an API with HTTP proxy integration
<a name="api-gateway-create-api-as-simple-proxy-for-http-test"></a>

 Whether a particular client request succeeds depends on the following: 
+  If the backend has made the corresponding backend endpoint available and, if so, has granted the required access permissions. 
+ If the client supplies the correct input.

For example, the PetStore API used here does not expose the `/petstore` resource. As such, you get a `404 Resource Not Found` response containing the error message of `Cannot GET /petstore`. 

In addition, the client must be able to handle the output format of the backend in order to parse the result correctly. API Gateway does not mediate to facilitate interactions between the client and backend. 

**To test an API integrated with the PetStore website using HTTP proxy integration through the proxy resource**

1. Select the **Test** tab. You might need to choose the right arrow button to show the tab.

1. For **Method type**, select `GET`.

1. For **Path**, under **proxy**, enter **petstore/pets**.

1. For **Query strings**, enter **type=fish**.

1. Choose **Test**.

     
![\[Use the test feature to test a method.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/api-gateway-simple-proxy-petstore-call-proxy-resource-new-console.png)

   Because the backend website supports the `GET /petstore/pets?type=fish` request, it returns a successful response similar to the following:

   ```
   [
     {
       "id": 1,
       "type": "fish",
       "price": 249.99
     },
     {
       "id": 2,
       "type": "fish",
       "price": 124.99
     },
     {
       "id": 3,
       "type": "fish",
       "price": 0.99
     }
   ]
   ```

   If you try to call `GET /petstore`, you get a `404` response with an error message of `Cannot GET /petstore`. This is because the backend does not support the specified operation. If you call `GET /petstore/pets/1`, you get a `200 OK` response with the following payload, because the request is supported by the PetStore website.

   ```
   {
     "id": 1,
     "type": "dog",
     "price": 249.99
   }
   ```

You can also use a browser to test your API. Deploy your API and associate it to a stage to create your API's Invoke URL.

**To deploy your API**

1. Choose **Deploy API**.

1. For **Stage**, select **New stage**.

1. For **Stage name**, enter **test**.

1. (Optional) For **Description**, enter a description.

1. Choose **Deploy**.

Now clients can call your API. 

**To invoke your API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose your API.

1. In the main navigation pane, choose **Stage**.

1. Under **Stage details**, choose the copy icon to copy your API's invoke URL.

   Enter your API's invoke URL in a web browser. 

   The full URL should look like `https://abcdef123.execute-api.us-east-2.amazonaws.com/test/petstore/pets?type=fish`. 

   Your browser sends a `GET` request to the API.

1. The result should be the same as returned when you use **Test** in the API Gateway console.

# Tutorial: Create a REST API with an HTTP non-proxy integration
<a name="api-gateway-create-api-step-by-step"></a>

 In this tutorial, you create an API from scratch using the Amazon API Gateway console. You can think of the console as an API design studio and use it to scope the API features, to experiment with its behaviors, to build the API, and to deploy your API in stages. 

**Topics**
+ [

## Create an API with HTTP custom integration
](#api-gateway-create-resource-and-methods)
+ [

## (Optional) Map request parameters
](#api-gateway-create-resources-and-methods-next-steps)

## Create an API with HTTP custom integration
<a name="api-gateway-create-resource-and-methods"></a>

 This section walks you through the steps to create resources, expose methods on a resource, configure a method to achieve the desired API behaviors, and to test and deploy the API.

In this step, you create an empty API. In the following steps you create resources and methods to connect your API to the `http://petstore-demo-endpoint.execute-api.com/petstore/pets` endpoint, using a non-proxy HTTP integration. 

**To create an API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. If this is your first time using API Gateway, you see a page that introduces you to the features of the service. Under **REST API**, choose **Build**. When the **Create Example API** popup appears, choose **OK**.

   If this is not your first time using API Gateway, choose **Create API**. Under **REST API**, choose **Build**.

1.  For **API name**, enter **HTTPNonProxyAPI**.

1. (Optional) For **Description**, enter a description.

1. Keep **API endpoint type** set to **Regional**.

1. For **IP address type**, select **IPv4**.

1. Choose **Create API**.

The **Resources** tree shows the root resource (`/`) without any methods. In this exercise, we will build the API with the HTTP custom integration of the PetStore website (http://petstore-demo-endpoint.execute-api.com/petstore/pets.) For illustration purposes, we will create a `/pets` resource as a child of the root and expose a GET method on this resource for a client to retrieve a list of available Pets items from the PetStore website.

**To create a /pets resource**

1. Choose **Create resource**.

1. Keep **Proxy resource** turned off.

1. Keep **Resource path** as `/`.

1. For **Resource name**, enter **pets**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

In this step, you create a `GET` method on the **/pets** resource. The `GET` method is integrated with the `http://petstore-demo-endpoint.execute-api.com/petstore/pets` website. Other options for an API method include the following:
+ **POST**, primarily used to create child resources.
+ **PUT**, primarily used to update existing resources (and, although not recommended, can be used to create child resources).
+ **DELETE**, used to delete resources.
+ **PATCH**, used to update resources.
+ **HEAD**, primarily used in testing scenarios. It is the same as GET but does not return the resource representation.
+ **OPTIONS**, which can be used by callers to get information about available communication options for the target service.

 For the integration request's **HTTP method**, you must choose one supported by the backend. For `HTTP` or `Mock integration`, it makes sense that the method request and the integration request use the same HTTP verb. For other integration types the method request will likely use an HTTP verb different from the integration request. For example, to call a Lambda function, the integration request must use `POST` to invoke the function, whereas the method request may use any HTTP verb depending on the logic of the Lambda function. 

**To create a `GET` method on the **/pets** resource**

1. Select the **/pets** resource.

1. Choose **Create method**.

1. For **Method type**, select **GET**.

1. For **Integration type**, select **HTTP integration**.

1. Keep **HTTP proxy integration** turned off.

1. For **HTTP method**, select **GET**.

1. For **Endpoint URL**, enter **http://petstore-demo-endpoint.execute-api.com/petstore/pets**.

   The PetStore website allows you to retrieve a list of `Pet` items by the pet type, such as "Dog" or "Cat", on a given page.

1. For **Content handling**, select **Passthrough**.

1. Choose **URL query string parameters**.

   The PetStore website uses the `type` and `page` query string parameters to accept an input. You add query string parameters to the method request and map them into corresponding query string parameters of the integration request. 

1. To add the query string parameters, do the following:

   1. Choose **Add query string**.

   1. For **Name**, enter **type**

   1. Keep **Required** and **Caching** turned off.

   Repeat the previous steps to create an additional query string with the name **page**.

1. Choose **Create method**.

The client can now supply a pet type and a page number as query string parameters when submitting a request. These input parameters must be mapped into the integration's query string parameters to forward the input values to our PetStore website in the backend.

**To map input parameters to the Integration request**

1. On the **Integration request** tab, under **Integration request settings**, choose **Edit**.

1. Choose **URL query string parameters**, and then do the following: 

   1. Choose **Add query string parameter**.

   1. For **Name**, enter **type**.

   1. For **Mapped from**, enter **method.request.querystring.type**

   1. Keep **Caching** turned off. 

   1. Choose **Add query string parameter**.

   1. For **Name**, enter **page**.

   1. For **Mapped from**, enter **method.request.querystring.page**

   1. Keep **Caching** turned off. 

1. Choose **Save**.

**To test the API**

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. For **Query strings**, enter **type=Dog&page=2**.

1. Choose **Test**.

    The result is similar to the following:

      
![\[Test-invoke GET on pets method result\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/api-gateway-create-api-step-by-step-test-invoke-get-on-pets-result-new-console.png)

    Now that the test is successful, we can deploy the API to make it publicly available. 

1. Choose **Deploy API**.

1. For **Stage**, select **New stage**.

1. For **Stage name**, enter **Prod**.

1. (Optional) For **Description**, enter a description.

1. Choose **Deploy**.

1.  (Optional) Under **Stage details**, for **Invoke URL**, you can choose the copy icon to copy your API's invoke URL. You can use this with tools such as [Postman](https://www.postman.com) and [cURL](https://curl.se/) to test your API.

 If you use an SDK to create a client, you can call the methods exposed by the SDK to sign the request. For implementation details, see the [AWS SDK](https://aws.amazon.com/developer/tools/) of your choosing. 

**Note**  
 When changes are made to your API, you must redeploy the API to make the new or updated features available before invoking the request URL again. 

## (Optional) Map request parameters
<a name="api-gateway-create-resources-and-methods-next-steps"></a>

### Map request parameters for an API Gateway API
<a name="getting-started-mappings"></a>

 This tutorial shows how to create a path parameter of `{petId}` on the API's method request to specify an item ID, map it to the `{id}` path parameter in the integration request URL, and send the request to the HTTP endpoint.

**Note**  
 If you enter the incorrect case of a letter, such as lowercase letter instead of an uppercase letter, this will cause errors later in the walkthrough. 

#### Step 1: Create resources
<a name="getting-started-mappings-add-resources"></a>

In this step, you create a resource with a path parameter \$1petId\$1.

**To create the \$1petId\$1 resource**

1. Select the **/pets** resource, and then choose **Create resource**.

1. Keep **Proxy resource** turned off.

1. For **Resource path**, select **/pets/**.

1. For **Resource name**, enter **\$1petId\$1**.

    Use the curly braces (`{ }`) around `petId` so that **/pets/\$1petId\$1** is displayed.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

#### Step 2: Create and test the methods
<a name="getting-started-mappings-set-methods"></a>

 In this step, you create a `GET` method with a `{petId}` path parameter. 

**To set up GET method**

1. Select the **/\$1petId\$1** resource, and then choose **Create method**.

1. For **Method type**, select **GET**.

1. For **Integration type**, select **HTTP integration**.

1. Keep **HTTP proxy integration** turned off.

1. For **HTTP method**, select **GET**.

1. For **Endpoint URL**, enter **http://petstore-demo-endpoint.execute-api.com/petstore/pets/\$1id\$1**

1. For **Content handling**, select **Passthrough**.

1. Keep the **Default timeout** turned on. 

1. Choose **Create method**.

Now you map the `{petId}` path parameter that you just created to the `{id}` path parameter in the HTTP endpoint URL of the integration request. The HTTP endpoint URL was **http://petstore-demo-endpoint.execute-api.com/petstore/pets/\$1id\$1**.

**To map the `{petId}` path parameter**

1. On the **Integration request** tab, under **Integration request settings**, choose **Edit**.

1. Choose **URL path parameters**.

1.  API Gateway creates a path parameter for the integration request named **petId**, however this path parameter isn't valid for the HTTP endpoint URL that you set as the backend integration. The HTTP endpoint uses `{id}` as the path parameter. For **Name**, delete **petId** and enter **id**.

   This maps the method request's path parameter of `petId` to the integration request's path parameter of `id`.

1. Choose **Save**.

Now you test the method.

**To test the method**

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. Under **Path** for **petId**, enter **4**.

1. Choose **Test**.

   If successful, **Response body** displays the following:

   ```
   {
     "id": 4,
     "type": "bird",
     "price": 999.99
   }
   ```

#### Step 3: Deploy the API
<a name="getting-started-mappings-deploy"></a>

In this step, you deploy the API so that you can begin calling it outside of the API Gateway console.

**To deploy the API**

1. Choose **Deploy API**.

1. For **Stage**, select **Prod**.

1. (Optional) For **Description**, enter a description.

1. Choose **Deploy**.

#### Step 4: Test the API
<a name="getting-started-mappings-test"></a>

In this step, you go outside of the API Gateway console and use your API to access the HTTP endpoint.

1. In the main navigation pane, choose **Stage**.

1. Under **Stage details**, choose the copy icon to copy your API's invoke URL.

   It should look something like this:

   ```
   https://my-api-id.execute-api.region-id.amazonaws.com/prod
   ```

1. Enter this URL in the address box of a new browser tab and append `/pets/4` to the URL before you submit your request.

1. The browser will return the following:

   ```
   {
     "id": 4,
     "type": "bird",
     "price": 999.99
   }
   ```

#### Next steps
<a name="api-gateway-create-resources-and-methods-next-steps"></a>

You can further customize your API by turning on request validation, transforming data, or creating custom gateway responses. 

To explore more ways to customize your API, see the following tutorials:
+ For more information about request validation, see [Set up basic request validation in API Gateway](api-gateway-request-validation-set-up.md).
+ For information about how to transform request and response payloads, see [Tutorial: Modify the integration request and response for integrations to AWS services](set-up-data-transformations-in-api-gateway.md).
+ For information about how to create custom gateway responses see, [Set up a gateway response for a REST API using the API Gateway console](set-up-gateway-response-using-the-console.md).

# Tutorial: Create a REST API with a private integration
<a name="getting-started-with-private-integration"></a>

In this tutorial, you create a REST API that connects to an Amazon ECS service that runs in an Amazon VPC. Clients outside of your Amazon VPC can use the API to access your Amazon ECS service. 

This tutorial takes approximately an hour to complete. First, you use an CloudFormation template to create a Amazon VPC and Amazon ECS service. Then you use the API Gateway console to create a VPC link V2. The VPC link allows API Gateway to access the Amazon ECS service that runs in your Amazon VPC. Next, you create a REST API that uses the VPC link V2 to connect to your Amazon ECS service. Lastly, you test your API.

When you invoke your REST API, API Gateway routes the request to your Amazon ECS service through your VPC link V2, and then returns the response from the service.

**Note**  
This tutorial was previously supported for HTTP APIs, and now is supported for REST APIs using VPC link V2.

![\[Overview of the REST API you create in this tutorial.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/private-integration-rest.png)


To complete this tutorial, you need an AWS account and an AWS Identity and Access Management user with console access. For more information, see [Set up to use API Gateway](setting-up.md).

**Topics**
+ [

## Step 1: Create an Amazon ECS service
](#rest-api-private-integration-create-ecs-service)
+ [

## Step 2: Create a VPC link
](#http-api-private-integration-vpc-link)
+ [

## Step 3: Create a REST API
](#http-api-private-integration-create-api)
+ [

## Step 4: Test your API
](#rest-api-private-integration-test-api)
+ [

## Step 5: Deploy your API
](#rest-api-private-integration-deploy-api)
+ [

## Step 6: Call your API
](#rest-api-private-integration-call)
+ [

## Step 7: Clean up
](#rest-api-private-integration-cleanup)

## Step 1: Create an Amazon ECS service
<a name="rest-api-private-integration-create-ecs-service"></a>

Amazon ECS is a container management service that makes it easy to run, stop, and manage Docker containers on a cluster. In this tutorial, you run your cluster on a serverless infrastructure that's managed by Amazon ECS.

Download and unzip [this CloudFormation template](samples/rest-private-integration-tutorial.zip), which creates all of the dependencies for the service, including an Amazon VPC. You use the template to create an Amazon ECS service that uses an Application Load Balancer.

**To create an CloudFormation stack**

1. Open the CloudFormation console at [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/).

1. Choose **Create stack** and then choose **With new resources (standard)**.

1. For **Specify template**, choose **Upload a template file**.

1. Select the template that you downloaded.

1. Choose **Next**. 

1. For **Stack name**, enter **rest-api-private-integrations-tutorial** and then choose **Next**.

1. For **Configure stack options**, choose **Next**.

1. For **Capabilities**, acknowledge that CloudFormation can create IAM resources in your account.

1. Choose **Next**, and then choose **Submit**.

CloudFormation provisions the ECS service, which can take a few minutes. When the status of your CloudFormation stack is **CREATE\$1COMPLETE**, you're ready to move on to the next step.

## Step 2: Create a VPC link
<a name="http-api-private-integration-vpc-link"></a>

A VPC link allows API Gateway to access private resources in an Amazon VPC. You use a VPC link to allow clients to access your Amazon ECS service through your REST API.

**To create a VPC link**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. On the main navigation pane, choose **VPC links** and then choose **Create**.

   You might need to choose the menu icon to open the main navigation pane.

1. For **Choose a VPC link version**, select **VPC link V2**.

1. For **Name**, enter **private-integrations-tutorial**.

1. For **VPC**, choose the VPC that you created in step 1. The name should start with **RestApiStack**.

1. For **Subnets**, select the two private subnets in your VPC. Their names end with `PrivateSubnet`.

1. For **Security groups**, select the Group ID that starts with `private-integrations-tutorial` and has the description of `RestApiStack/RestApiTutorialService/Service/SecurityGroup`.

1. Choose **Create**.

After you create your VPC link V2, API Gateway provisions Elastic Network Interfaces to access your VPC. The process can take a few minutes. In the meantime, you can create your API.

## Step 3: Create a REST API
<a name="http-api-private-integration-create-api"></a>

The REST API provides an HTTP endpoint for your Amazon ECS service.



**To create a REST API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose **Create API**, and then for **REST API**, choose **Build**.

1. For **Name**, enter **private-integration-api**.

1. For **IP address type**, select **IPv4**.

1. Choose **Create API**.

   After you create your API, you create a method.

1. Choose **Create method**, and then do the following:

   1. For **Method type**, select `GET`.

   1. For **Integration type**, select **VPC link**.

   1. Turn on **VPC proxy integration**.

   1. For **HTTP method**, select `GET`.

   1. For **VPC link**, choose the VPC link V2 you created in the previous step.

   1. For **Integration target**, enter the load balancer that you created with the CloudFormation template in Step 1. It's name should start with **rest-**.

   1. For **Endpoint URL**, enter `http://private-integrations-tutorial.com`.

      The URL is used to set the `Host` header of the integration request. In this case, the host header is **private-integrations-tutorial**.

   1. Choose **Create method**.

      With the proxy integration, the API is ready to test.

## Step 4: Test your API
<a name="rest-api-private-integration-test-api"></a>

Next, you test invoking the API method.

**To test your API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose your API.

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. Choose **Test**

   Verify that your API's response is a welcome message that tells you that your app is running on Amazon ECS.

## Step 5: Deploy your API
<a name="rest-api-private-integration-deploy-api"></a>

Next, you deploy your API.

**To deploy your API**

1. Choose **Deploy API**.

1. For **Stage**, select **New stage**.

1. For **Stage name**, enter **Prod**.

1. (Optional) For **Description**, enter a description.

1. Choose **Deploy**.

## Step 6: Call your API
<a name="rest-api-private-integration-call"></a>

After your API is deployed, you can call it.

**To call your API**

1. Enter the invoke URL in a web browser.

   The full URL should look like `https://abcd123.execute-api.us-east-2.amazonaws.com/Prod`. 

   Your browser sends a `GET` request to the API.

1. Verify that your API's response is a welcome message that tells you that your app is running on Amazon ECS.

   If you see the welcome message, you successfully created an Amazon ECS service that runs in an Amazon VPC, and you used an API Gateway REST API with a VPC link V2 to access the Amazon ECS service.

## Step 7: Clean up
<a name="rest-api-private-integration-cleanup"></a>

To prevent unnecessary costs, delete the resources that you created as part of this tutorial. The following steps delete your VPC link V2, CloudFormation stack, and REST API.

**To delete a REST API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. On the **APIs** page, select an API. Choose **Actions**, choose **Delete**, and then confirm your choice.

**To delete a VPC link**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose **VPC link**.

1. Select your VPC link, choose **Delete**, and then confirm your choice.

**To delete an CloudFormation stack**

1. Open the CloudFormation console at [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/).

1. Select your CloudFormation stack.

1. Choose **Delete** and then confirm your choice.

# Tutorial: Create a REST API with an AWS integration
<a name="getting-started-aws-proxy"></a>

 Both the [Tutorial: Create a REST API with a Lambda proxy integration](api-gateway-create-api-as-simple-proxy-for-lambda.md) and [Tutorial: Create a REST API with a Lambda non-proxy integration](getting-started-lambda-non-proxy-integration.md) topics describe how to create an API Gateway API to expose the integrated Lambda function. In addition, you can create an API Gateway API to expose other AWS services, such as Amazon SNS, Amazon S3, Amazon Kinesis, and even AWS Lambda. This is made possible by the `AWS` integration. The Lambda integration or the Lambda proxy integration is a special case, where the Lambda function invocation is exposed through the API Gateway API. 

 All AWS services support dedicated APIs to expose their features. However, the application protocols or programming interfaces are likely to differ from service to service. An API Gateway API with the `AWS` integration has the advantage of providing a consistent application protocol for your client to access different AWS services. 

 In this walkthrough, we create an API to expose Amazon SNS. For more examples of integrating an API with other AWS services, see [Amazon API Gateway tutorials and workshops](api-gateway-tutorials.md). 

 Unlike the Lambda proxy integration, there is no corresponding proxy integration for other AWS services. Hence, an API method is integrated with a single AWS action. For more flexibility, similar to the proxy integration, you can set up a Lambda proxy integration. The Lambda function then parses and processes requests for other AWS actions. 

 API Gateway does not retry when the endpoint times out. The API caller must implement retry logic to handle endpoint timeouts. 

 This walkthrough builds on the instructions and concepts in [Tutorial: Create a REST API with a Lambda non-proxy integration](getting-started-lambda-non-proxy-integration.md). If you have not yet completed that walkthrough, we suggest that you do it first. 



**Topics**
+ [

## Prerequisites
](#getting-started-aws-proxy-prerequisites)
+ [

## Step 1: Create the AWS service proxy execution role
](#getting-started-aws-proxy-add-roles)
+ [

## Step 2: Create the resource
](#getting-started-aws-proxy-add-resources)
+ [

## Step 3: Create the GET method
](#getting-started-aws-proxy-add-methods)
+ [

## Step 4: Specify method settings and test the method
](#getting-started-aws-proxy-set-methods)
+ [

## Step 5: Deploy the API
](#getting-started-aws-proxy-deploy)
+ [

## Step 6: Test the API
](#getting-started-aws-proxy-test)
+ [

## Step 7: Clean up
](#getting-started-aws-proxy-clean-up)

## Prerequisites
<a name="getting-started-aws-proxy-prerequisites"></a>

Before you begin this walkthrough, do the following:

1. Complete the steps in [Set up to use API Gateway](setting-up.md).

1.  Create a new API named `MyDemoAPI`. For more information, see [Tutorial: Create a REST API with an HTTP non-proxy integration](api-gateway-create-api-step-by-step.md). 

1. Deploy the API at least once to a stage named `test`. For more information, see [Deploy the API](getting-started-lambda-non-proxy-integration.md#getting-started-deploy-api) in [Choose an AWS Lambda integration tutorial](getting-started-with-lambda-integration.md).

1. Complete the rest of the steps in [Choose an AWS Lambda integration tutorial](getting-started-with-lambda-integration.md).

1. Create at least one topic in Amazon Simple Notification Service (Amazon SNS). You will use the deployed API to get a list of topics in Amazon SNS that are associated with your AWS account. To learn how to create a topic in Amazon SNS, see [Create a Topic](https://docs.aws.amazon.com/sns/latest/dg/sns-create-topic.html). (You do not need to copy the topic ARN mentioned in step 5.)

## Step 1: Create the AWS service proxy execution role
<a name="getting-started-aws-proxy-add-roles"></a>

 To allow the API to invoke Amazon SNS actions, you must have the appropriate IAM policies attached to an IAM role. In this step, you create a new IAM role.

**To create the AWS service proxy execution role**

1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. Choose **Roles**.

1. Choose **Create role**.

1.  Choose **AWS service** under **Select type of trusted entity**, and then select **API Gateway** and select **Allows API Gateway to push logs to CloudWatch Logs**.

1.  Choose **Next**, and then choose **Next**.

1. For **Role name**, enter **APIGatewaySNSProxyPolicy**, and then choose **Create role**.

1. In the **Roles** list, choose the role you just created. You may need to scroll or use the search bar to find the role.

1. For the selected role, select the **Add permissions** tab.

1. Choose **Attach policies** from the dropdown list.

1. In the search bar, enter **AmazonSNSReadOnlyAccess** and choose **Add permissions**. 
**Note**  
This tutorial uses a managed policy for simplicity. As a best practice, you should create your own IAM policy to grant the minimum permissions required. 

1. Note the newly created **Role ARN**, you will use it later.

## Step 2: Create the resource
<a name="getting-started-aws-proxy-add-resources"></a>

In this step, you create a resource that enables the AWS service proxy to interact with the AWS service.

**To create the resource**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose your API.

1. Select the root resource, **/**, represented by a single forward slash (**/**), and then choose **Create resource**.

1. Keep **Proxy resource** turned off.

1. Keep **Resource path** as `/`.

1. For **Resource name**, enter **mydemoawsproxy**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

## Step 3: Create the GET method
<a name="getting-started-aws-proxy-add-methods"></a>

In this step, you create a GET method that enables the AWS service proxy to interact with the AWS service.

**To create the `GET` method**

1. Select the **/mydemoawsproxy** resource, and then choose **Create method**.

1. For method type, select **GET**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Amazon SNS topic.

1. For **AWS service**, select **Amazon SNS**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, select **GET**.

1. For **Action type**, select **Use action name**.

1. For **Action name**, enter **ListTopics**.

1. For **Execution role**, enter the role ARN for **APIGatewaySNSProxyPolicy**.

1. Choose **Create method**.

## Step 4: Specify method settings and test the method
<a name="getting-started-aws-proxy-set-methods"></a>

You can now test your `GET` method to verify that it has been properly set up to list your Amazon SNS topics.

**To test the `GET` method**

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. Choose **Test**.

   The result displays response similar to the following:

   ```
   {
     "ListTopicsResponse": {
       "ListTopicsResult": {
         "NextToken": null,
         "Topics": [
           {
             "TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-1"
           },
           {
             "TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-2"
           },
           ...
           {
             "TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-N"
           }
         ]
       },
       "ResponseMetadata": {
         "RequestId": "abc1de23-45fa-6789-b0c1-d2e345fa6b78"
       }
     }
   }
   ```

## Step 5: Deploy the API
<a name="getting-started-aws-proxy-deploy"></a>

In this step, you deploy the API so that you can call it from outside of the API Gateway console.

**To deploy the API**

1. Choose **Deploy API**.

1. For **Stage**, select **New stage**.

1. For **Stage name**, enter **test**.

1. (Optional) For **Description**, enter a description.

1. Choose **Deploy**.

## Step 6: Test the API
<a name="getting-started-aws-proxy-test"></a>

In this step, you go outside of the API Gateway console and use your AWS service proxy to interact with the Amazon SNS service.

1. In the main navigation pane, choose **Stage**.

1. Under **Stage details**, choose the copy icon to copy your API's invoke URL.

   It should look like this:

   ```
   https://my-api-id.execute-api.region-id.amazonaws.com/test
   ```

1. Enter the URL into the address box of a new browser tab.

1. Append `/mydemoawsproxy` so that the URL looks like this:

   ```
   https://my-api-id.execute-api.region-id.amazonaws.com/test/mydemoawsproxy
   ```

   Browse to the URL. Information similar to the following should be displayed:

   ```
   {"ListTopicsResponse":{"ListTopicsResult":{"NextToken": null,"Topics":[{"TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-1"},{"TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-2"},...{"TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-N}]},"ResponseMetadata":{"RequestId":"abc1de23-45fa-6789-b0c1-d2e345fa6b78}}}
   ```

## Step 7: Clean up
<a name="getting-started-aws-proxy-clean-up"></a>

You can delete the IAM resources the AWS service proxy needs to work.

**Warning**  
If you delete an IAM resource an AWS service proxy relies on, that AWS service proxy and any APIs that rely on it will no longer work. Deleting an IAM resource cannot be undone. If you want to use the IAM resource again, you must re-create it.

**To delete the associated IAM resources**

1. Open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. In the **Details** area, choose **Roles**.

1. Select **APIGatewayAWSProxyExecRole**, and then choose **Role Actions**, **Delete Role**. When prompted, choose **Yes, Delete**.

1. In the **Details** area, choose **Policies**.

1. Select **APIGatewayAWSProxyExecPolicy**, and then choose **Policy Actions**, **Delete**. When prompted, choose **Delete**.

 You have reached the end of this walkthrough. For more detailed discussions about creating API as an AWS service proxy, see [Tutorial: Create a REST API as an Amazon S3 proxy](integrating-api-with-aws-services-s3.md), [Tutorial: Create a calculator REST API with two AWS service integrations and one Lambda non-proxy integration](integrating-api-with-aws-services-lambda.md), or [Tutorial: Create a REST API as an Amazon Kinesis proxy](integrating-api-with-aws-services-kinesis.md). 

# Tutorial: Create a calculator REST API with two AWS service integrations and one Lambda non-proxy integration
<a name="integrating-api-with-aws-services-lambda"></a>

The [Tutorial: Create a REST API with a Lambda non-proxy integration](getting-started-lambda-non-proxy-integration.md) uses `Lambda Function` integration exclusively. `Lambda Function` integration is a special case of the `AWS Service` integration type that performs much of the integration setup for you, such as automatically adding the required resource-based permissions for invoking the Lambda function. Here, two of the three integrations use `AWS Service` integration. In this integration type, you have more control, but you'll need to manually perform tasks like creating and specifying an IAM role containing appropriate permissions.



In this tutorial, you'll create a `Calc` Lambda function that implements basic arithmetic operations, accepting and returning JSON-formatted input and output. Then you'll create a REST API and integrate it with the Lambda function in the following ways:

1. By exposing a `GET` method on the `/calc` resource to invoke the Lambda function, supplying the input as query string parameters. (`AWS Service` integration)

1. By exposing a `POST` method on the `/calc` resource to invoke the Lambda function, supplying the input in the method request payload. (`AWS Service` integration)

1. By exposing a `GET` on nested `/calc/{operand1}/{operand2}/{operator}` resources to invoke the Lambda function, supplying the input as path parameters. (`Lambda Function` integration)

In addition to trying out this tutorial, you may wish to study the [OpenAPI definition file](api-as-lambda-proxy-export-swagger-with-extensions.md) for the `Calc` API, which you can import into API Gateway by following the instructions in [Develop REST APIs using OpenAPI in API Gateway](api-gateway-import-api.md).

**Topics**
+ [

## Create an assumable IAM role
](#api-as-lambda-proxy-setup-iam-role-policies)
+ [

## Create a `Calc` Lambda function
](#api-as-lambda-proxy-create-lambda-function)
+ [

## Test the `Calc` Lambda function
](#api-as-lambda-proxy-test-lambda-function-)
+ [

## Create a `Calc` API
](#api-as-lambda-proxy-create-api-resources)
+ [

## Integration 1: Create a `GET` method with query parameters to call the Lambda function
](#api-as-lambda-proxy-expose-get-method-with-query-strings-to-call-lambda-function)
+ [

## Integration 2: Create a `POST` method with a JSON payload to call the Lambda function
](#api-as-lambda-proxy-expose-post-method-with-json-body-to-call-lambda-function)
+ [

## Integration 3: Create a `GET` method with path parameters to call the Lambda function
](#api-as-lambda-proxy-expose-get-method-with-path-parameters-to-call-lambda-function)
+ [

# OpenAPI definitions of sample API integrated with a Lambda function
](api-as-lambda-proxy-export-swagger-with-extensions.md)

## Create an assumable IAM role
<a name="api-as-lambda-proxy-setup-iam-role-policies"></a>

In order for your API to invoke your `Calc` Lambda function, you'll need to have an API Gateway assumable IAM role, which is an IAM role with the following trusted relationship:

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

------

The role you create will need to have Lambda [InvokeFunction](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html) permission. Otherwise, the API caller will receive a `500 Internal Server Error` response. To give the role this permission, you'll attach the following IAM policy to it:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "lambda:InvokeFunction",
            "Resource": "*"
        }
    ]
}
```

------

Here's how to accomplish all this:

**Create an API Gateway assumable IAM role**

1. Log in to the IAM console.

1. Choose **Roles**.

1. Choose **Create Role**.

1. Under **Select type of trusted entity**, choose **AWS Service**.

1. Under **Choose the service that will use this role**, choose **Lambda**.

1. Choose **Next: Permissions**.

1. Choose **Create Policy**.

   A new **Create Policy** console window will open up. In that window, do the following:

   1. In the **JSON** tab, replace the existing policy with the following:

------
#### [ JSON ]

****  

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "lambda:InvokeFunction",
                  "Resource": "*"
              }
          ]
      }
      ```

------

   1. Choose **Review policy**.

   1. Under **Review Policy**, do the following:

      1. For **Name**, type a name such as **lambda\$1execute**.

      1. Choose **Create Policy**.

1. In the original **Create Role** console window, do the following:

   1. Under **Attach permissions policies**, choose your **lambda\$1execute** policy from the dropdown list.

      If you don't see your policy in the list, choose the refresh button at the top of the list. (Don't refresh the browser page\$1)

   1. Choose **Next:Tags**.

   1. Choose **Next:Review**.

   1. For the **Role name**, type a name such as **lambda\$1invoke\$1function\$1assume\$1apigw\$1role**.

   1. Choose **Create role**.

1. Choose your **lambda\$1invoke\$1function\$1assume\$1apigw\$1role** from the list of roles.

1. Choose the **Trust relationships** tab.

1. Choose **Edit trust relationship**.

1. Replace the existing policy with the following:

------
#### [ JSON ]

****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Sid": "",
         "Effect": "Allow",
         "Principal": {
           "Service": [
             "lambda.amazonaws.com",
             "apigateway.amazonaws.com"
           ]
         },
         "Action": "sts:AssumeRole"
       }
     ]
   }
   ```

------

1. Choose **Update Trust Policy**.

1. Make a note of the role ARN for the role you just created. You'll need it later.

## Create a `Calc` Lambda function
<a name="api-as-lambda-proxy-create-lambda-function"></a>

Next you'll create a Lambda function using the Lambda console.

1. In the Lambda console, choose **Create function**.

1. Choose **Author from Scratch**.

1. For **Name**, enter **Calc**.

1. For **Runtime**, choose either the latest supported **Node.js** or **Python** runtime.

1. For all other options, use the default setting.

1. Choose **Create function**.

1.  Copy the following Lambda function in your preferred runtime and paste it into the code editor in the Lambda console. 

------
#### [ Node.js ]

   ```
   export const handler = async function (event, context) {
     console.log("Received event:", JSON.stringify(event));
   
     if (
       event.a === undefined ||
       event.b === undefined ||
       event.op === undefined
     ) {
       return "400 Invalid Input";
     }
   
     const res = {};
     res.a = Number(event.a);
     res.b = Number(event.b);
     res.op = event.op;
     if (isNaN(event.a) || isNaN(event.b)) {
       return "400 Invalid Operand";
     }
     switch (event.op) {
       case "+":
       case "add":
         res.c = res.a + res.b;
         break;
       case "-":
       case "sub":
         res.c = res.a - res.b;
         break;
       case "*":
       case "mul":
         res.c = res.a * res.b;
         break;
       case "/":
       case "div":
         if (res.b == 0) {
           return "400 Divide by Zero";
         } else {
           res.c = res.a / res.b;
         }
         break;
       default:
         return "400 Invalid Operator";
     }
   
     return res;
   };
   ```

------
#### [ Python ]

   ```
   import json
   
   
   def lambda_handler(event, context):
       print(event)
   
       try:
           (event['a']) and (event['b']) and (event['op'])
       except KeyError:
           return '400 Invalid Input'
   
       try:
           res = {
               "a": float(
                   event['a']), "b": float(
                   event['b']), "op": event['op']}
       except ValueError:
           return '400 Invalid Operand'
   
       if event['op'] == '+':
           res['c'] = res['a'] + res['b']
       elif event['op'] == '-':
           res['c'] = res['a'] - res['b']
       elif event['op'] == '*':
           res['c'] = res['a'] * res['b']
       elif event['op'] == '/':
           if res['b'] == 0:
               return '400 Divide by Zero'
           else:
               res['c'] = res['a'] / res['b']
       else:
           return '400 Invalid Operator'
   
       return res
   ```

------

1. Under Execution role, choose **Choose an existing role**.

1. Enter the role ARN for the **lambda\$1invoke\$1function\$1assume\$1apigw\$1role** role you created earlier.

1. Choose **Deploy**.

 This function requires two operands (`a` and `b`) and an operator (`op`) from the `event` input parameter. The input is a JSON object of the following format: 

```
{
  "a": "Number" | "String",
  "b": "Number" | "String",
  "op": "String"
}
```

This function returns the calculated result (`c`) and the input. For an invalid input, the function returns either the null value or the "Invalid op" string as the result. The output is of the following JSON format: 

```
{
  "a": "Number",
  "b": "Number",
  "op": "String",
  "c": "Number" | "String"
}
```

You should test the function in the Lambda console before integrating it with the API in the next step. 

## Test the `Calc` Lambda function
<a name="api-as-lambda-proxy-test-lambda-function-"></a>

Here's how to test your `Calc` function in the Lambda console:

1. Choose the **Test** tab.

1. For the test event name, enter **calc2plus5**.

1. Replace the test event definition with the following:

   ```
   {
     "a": "2",
     "b": "5",
     "op": "+"
   }
   ```

1. Choose **Save**.

1. Choose **Test**.

1. Expand **Execution result: succeeded**. You should see the following:

   ```
   {
     "a": 2,
     "b": 5,
     "op": "+",
     "c": 7
   }
   ```

## Create a `Calc` API
<a name="api-as-lambda-proxy-create-api-resources"></a>

The following procedure shows how to create an API for the `Calc` Lambda function you just created. In subsequent sections, you'll add resources and methods to it.

**To create an API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. If this is your first time using API Gateway, you see a page that introduces you to the features of the service. Under **REST API**, choose **Build**. When the **Create Example API** popup appears, choose **OK**.

   If this is not your first time using API Gateway, choose **Create API**. Under **REST API**, choose **Build**.

1.  For **API name**, enter **LambdaCalc**.

1. (Optional) For **Description**, enter a description.

1. Keep **API endpoint type** set to **Regional**.

1. For **IP address type**, select **IPv4**.

1. Choose **Create API**.

## Integration 1: Create a `GET` method with query parameters to call the Lambda function
<a name="api-as-lambda-proxy-expose-get-method-with-query-strings-to-call-lambda-function"></a>

By creating a `GET` method that passes query string parameters to the Lambda function, you enable the API to be invoked from a browser. This approach can be useful, especially for APIs that allow open access.

After you create an API, you create a resource. Typically, API resources are organized in a resource tree according to the application logic. For this step, you create a **/calc** resource. 

**To create a **/calc** resource**

1. Choose **Create resource**.

1. Keep **Proxy resource** turned off. 

1. Keep **Resource path** as `/`.

1. For **Resource name**, enter **calc**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

By creating a `GET` method that passes query string parameters to the Lambda function, you enable the API to be invoked from a browser. This approach can be useful, especially for APIs that allow open access.

In this method, Lambda requires that the `POST` request be used to invoke any Lambda function. This example shows that the HTTP method in a frontend method request can be different from the integration request in the backend.

**To create a `GET` method**

1. Select the **/calc** resource, and then choose **Create method**.

1. For **Method type**, select **GET**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Lambda function.

1. For **AWS service**, select **Lambda**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, select **POST**.

1. For **Action type**, select **Use path override**. This option allows us to specify the ARN of the [Invoke](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html) action to execute our `Calc` function. 

1. For **Path override**, enter **2015-03-31/functions/arn:aws:lambda:*us-east-2*:*account-id*:function:Calc/invocations**. For ** *account-id***, enter your AWS account ID. For ***us-east-2***, enter the AWS Region where you created your Lambda function. 

1. For **Execution role**, enter the role ARN for **lambda\$1invoke\$1function\$1assume\$1apigw\$1role**.

1. Do not change the settings of **Credential cache** and **Default timeout**.

1. Choose **Method request settings**.

1. For **Request validator**, select **Validate query string parameters and headers**.

   This setting will cause an error message to return if the client does not specify the required parameters.

1. Choose **URL query string parameters**.

   Now you set up query string parameters for the **GET** method on the **/calc** resource so it can receive input on behalf of the backend Lambda function.

   To create the query string parameters do the following:

   1. Choose **Add query string**.

   1. For **Name**, enter **operand1**.

   1. Turn on **Required**.

   1. Keep **Caching** turned off.

   Repeat the same steps and create a query string named **operand2** and a query string named **operator**.

1. Choose **Create method**.

Now, you create a mapping template to translate the client-supplied query strings to the integration request payload as required by the `Calc` function. This template maps the three query string parameters declared in **Method request** into designated property values of the JSON object as the input to the backend Lambda function. The transformed JSON object will be included as the integration request payload. 

**To map input parameters to the integration request**

1. On the **Integration request** tab, under **Integration request settings**, choose **Edit**.

1. For **Request body passthrough**, select **When there are no templates defined (recommended)**.

1. Choose **Mapping templates**.

1. Choose **Add mapping template**.

1. For **Content type**, enter **application/json**.

1. For **Template body**, enter the following code:

   ```
   {
       "a":  "$input.params('operand1')",
       "b":  "$input.params('operand2')", 
       "op": "$input.params('operator')"   
   }
   ```

1. Choose **Save**.

You can now test your `GET` method to verify that it has been properly set up to invoke the Lambda function.

**To test the `GET` method**

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. For **Query strings**, enter **operand1=2&operand2=3&operator=\$1**.

1. Choose **Test**.

   The results should look similar to this:  
![\[Create an API in API Gateway as a Lambda proxy\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/aws_proxy_lambda_calc_get_method_test_new_console.png)

## Integration 2: Create a `POST` method with a JSON payload to call the Lambda function
<a name="api-as-lambda-proxy-expose-post-method-with-json-body-to-call-lambda-function"></a>

By creating a `POST` method with a JSON payload to call the Lambda function, you make it so that the client must provide the necessary input to the backend function in the request body. To ensure that the client uploads the correct input data, you'll enable request validation on the payload.

**To create a `POST` method with a JSON payload**

1. Select the **/calc** resource, and then choose **Create method**.

1. For **Method type**, select **POST**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Lambda function.

1. For **AWS service**, select **Lambda**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, select **POST**.

1. For **Action type**, select **Use path override**. This option allows us to specify the ARN of the [Invoke](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html) action to execute our `Calc` function. 

1. For **Path override**, enter **2015-03-31/functions/arn:aws:lambda:*us-east-2*:*account-id*:function:Calc/invocations**. For ** *account-id***, enter your AWS account ID. For ***us-east-2***, enter the AWS Region where you created your Lambda function. 

1. For **Execution role**, enter the role ARN for **lambda\$1invoke\$1function\$1assume\$1apigw\$1role**.

1. Do not change the settings of **Credential cache** and **Default timeout**.

1. Choose **Create method**.

Now you create an **input** model to describe the input data structure and validate the incoming request body.

**To create an input model**

1. In the main navigation pane, choose **Models**.

1. Choose **Create model**.

1. For **Name**, enter **input**.

1. For **Content type**, enter **application/json**. 

   If no matching content type is found, request validation is not performed. To use the same model regardless of the content type, enter **\$1default**.

1. For **Model schema**, enter the following model:

   ```
   {
       "type":"object",
       "properties":{
           "a":{"type":"number"},
           "b":{"type":"number"},
           "op":{"type":"string"}
       },
       "title":"input"
   }
   ```

1. Choose **Create model**.

You now create an **output** model. This model describes the data structure of the calculated output from the backend. It can be used to map the integration response data to a different model. This tutorial relies on the passthrough behavior and does not use this model.

**To create an output model**

1. Choose **Create model**.

1. For **Name**, enter **output**.

1. For **Content type**, enter **application/json**. 

   If no matching content type is found, request validation is not performed. To use the same model regardless of the content type, enter **\$1default**.

1. For **Model schema**, enter the following model:

   ```
   {
       "type":"object",
       "properties":{
           "c":{"type":"number"}
       },
       "title":"output"
   }
   ```

1. Choose **Create model**.

You now create a **result** model. This model describes the data structure of the returned response data. It references both the **input** and **output** schemas defined in your API.

**To create a result model**

1. Choose **Create model**.

1. For **Name**, enter **result**.

1. For **Content type**, enter **application/json**. 

   If no matching content type is found, request validation is not performed. To use the same model regardless of the content type, enter **\$1default**.

1. For **Model schema**, enter the following model with your *restapi-id*. Your *restapi-id* is listed in parenthesis at the top of the console in the following flow: `API Gateway > APIs > LambdaCalc (abc123).`

   ```
   {
       "type":"object",
       "properties":{
           "input":{
               "$ref":"https://apigateway.amazonaws.com/restapis/restapi-id/models/input"
           },
           "output":{
               "$ref":"https://apigateway.amazonaws.com/restapis/restapi-id/models/output"
           }
       },
       "title":"result"
   }
   ```

1. Choose **Create model**.

You now configure the method request of your POST method to enable request validation on the incoming request body.

**To enable request validation on the POST method**

1. In the main navigation pane, choose **Resources**, and then select the `POST` method from the resource tree.

1. On the **Method request** tab, under **Method request settings**, choose **Edit**.

1. For **Request validator**, select **Validate body**.

1. Choose **Request body**, and then choose **Add model**.

1. For **Content type**, enter **application/json**.

   If no matching content type is found, request validation is not performed. To use the same model regardless of the content type, enter **\$1default**.

1. For **Model**, select **input**.

1. Choose **Save**.

You can now test your `POST` method to verify that it has been properly set up to invoke the Lambda function.

**To test the `POST` method**

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. For **Request body**, enter the following JSON payload.

   ```
   {
       "a": 1,
       "b": 2,
       "op": "+"
   }
   ```

1. Choose **Test**.

   You should see the following output:

   ```
   {
     "a": 1,
     "b": 2,
     "op": "+",
     "c": 3
   }
   ```

## Integration 3: Create a `GET` method with path parameters to call the Lambda function
<a name="api-as-lambda-proxy-expose-get-method-with-path-parameters-to-call-lambda-function"></a>

Now you'll create a `GET` method on a resource specified by a sequence of path parameters to call the backend Lambda function. The path parameter values specify the input data to the Lambda function. You'll use a mapping template to map the incoming path parameter values to the required integration request payload.

The resulting API resource structure will look like this:

![\[Create an API in API Gateway as a Lambda proxy\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/aws_proxy_lambda_create_api_resources_new_console.png)


**To create a **/\$1operand1\$1/\$1operand2\$1/\$1operator\$1** resource**

1. Choose **Create resource**.

1. For **Resource path**, select `/calc`.

1. For **Resource name**, enter **\$1operand1\$1**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

1. For **Resource path**, select `/calc/{operand1}/`.

1. For **Resource name**, enter **\$1operand2\$1**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

1. For **Resource path**, select `/calc/{operand1}/{operand2}/`.

1. For **Resource name**, enter **\$1operator\$1**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

This time you'll use the built-in Lambda integration in the API Gateway console to set up the method integration.

**To set up a method integration**

1. Select the **/\$1operand1\$1/\$1operand2\$1/\$1operator\$1** resource, and then choose **Create method**.

1. For **Method type**, select **GET**.

1. For **Integration type**, select **Lambda**.

1. Keep **Lambda proxy integration** turned off.

1. For **Lambda function**, select the AWS Region where you created your Lambda function and enter **Calc**.

1. Keep **Default timeout** turned on.

1. Choose **Create method**.

You now create a mapping template to map the three URL path parameters, declared when the **/calc/\$1operand1\$1/\$1operand2\$1/\$1operator\$1** resource was created, into designated property values in the JSON object. Because URL paths must be URL-encoded, the division operator must be specified as `%2F` instead of `/`. This template translates the `%2F` into `'/'` before passing it to the Lambda function. 

**To create a mapping template**

1. On the **Integration request** tab, under **Integration request settings**, choose **Edit**.

1. For **Request body passthrough**, select **When there are no templates defined (recommended)**.

1. Choose **Mapping templates**.

1. For **Content type**, enter **application/json**.

1. For **Template body**, enter the following code:

   ```
   {
      "a": "$input.params('operand1')",
      "b": "$input.params('operand2')",
      "op": #if($input.params('operator')=='%2F')"/"#{else}"$input.params('operator')"#end
   }
   ```

1. Choose **Save**.

You can now test your `GET` method to verify that it has been properly set up to invoke the Lambda function and pass the original output through the integration response without mapping. 

**To test the `GET` method**

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. For the **Path**, do the following:

   1. For **operand1**, enter **1**.

   1. For **operand2**, enter **1**.

   1. For **operator**, enter **\$1**.

1. Choose **Test**.

1. The result should look like this:  
![\[Test the GET method in the API Gateway console.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/aws_proxy_lambda_calc_get_method_test_path_parm_new_console.png)

Next, you model the data structure of the method response payload after the `result` schema.

By default, the method response body is assigned an empty model. This will cause the integration response body to be passed through without mapping. However, when you generate an SDK for one of the strongly-type languages, such as Java or Objective-C, your SDK users will receive an empty object as the result. To ensure that both the REST client and SDK clients receive the desired result, you must model the response data using a predefined schema. Here you'll define a model for the method response body and to construct a mapping template to translate the integration response body into the method response body.

**To create a method response**

1. On the **Method response** tab, under **Response 200**, choose **Edit**.

1. Under **Response body**, choose **Add model**.

1. For **Content type**, enter **application/json**.

1. For **Model**, select **result**.

1. Choose **Save**.

Setting the model for the method response body ensures that the response data will be cast into the `result` object of a given SDK. To make sure that the integration response data is mapped accordingly, you'll need a mapping template.

**To create a mapping template**

1. On the **Integration response** tab, under **Default - Response**, choose **Edit**.

1. Choose **Mapping templates**.

1. For **Content type**, enter **application/json**.

1. For **Template body**, enter the following code:

   ```
   #set($inputRoot = $input.path('$'))
   {
     "input" : {
       "a" : $inputRoot.a,
       "b" : $inputRoot.b,
       "op" : "$inputRoot.op"
     },
     "output" : {
       "c" : $inputRoot.c
     }
   }
   ```

1. Choose **Save**.

**To test the mapping template**

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. For the **Path**, do the following:

   1. For **operand1**, enter **1**.

   1. For **operand2**, enter **2**.

   1. For **operator**, enter **\$1**.

1. Choose **Test**.

1. The result will look like the following:

   ```
   {
     "input": {
       "a": 1,
       "b": 2,
       "op": "+"
     },
     "output": {
       "c": 3
     }
   }
   ```

At this point, you can only call the API using the **Test** feature in the API Gateway console. To make it available to clients, you'll need to deploy your API. Always be sure to redeploy your API whenever you add, modify, or delete a resource or method, update a data mapping, or update stage settings. Otherwise, new features or updates will not be available to clients of your API. as follows:

**To deploy the API**

1. Choose **Deploy API**.

1. For **Stage**, select **New stage**.

1. For **Stage name**, enter **Prod**.

1. (Optional) For **Description**, enter a description.

1. Choose **Deploy**.

1.  (Optional) Under **Stage details**, for **Invoke URL**, you can choose the copy icon to copy your API's invoke URL. You can use this with tools such as [Postman](https://www.postman.com) and [cURL](https://curl.se/) to test your API.

**Note**  
Always redeploy your API whenever you add, modify, or delete a resource or method, update a data mapping, or update stage settings. Otherwise, new features or updates will not be available to clients of your API.

# OpenAPI definitions of sample API integrated with a Lambda function
<a name="api-as-lambda-proxy-export-swagger-with-extensions"></a>

------
#### [ OpenAPI 2.0 ]

```
{
  "swagger": "2.0",
  "info": {
    "version": "2017-04-20T04:08:08Z",
    "title": "LambdaCalc"
  },
  "host": "uojnr9hd57.execute-api.us-east-1.amazonaws.com",
  "basePath": "/test",
  "schemes": [
    "https"
  ],
  "paths": {
    "/calc": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "operand2",
            "in": "query",
            "required": true,
            "type": "string"
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "type": "string"
          },
          {
            "name": "operand1",
            "in": "query",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            },
            "headers": {
              "operand_1": {
                "type": "string"
              },
              "operand_2": {
                "type": "string"
              },
              "operator": {
                "type": "string"
              }
            }
          }
        },
        "x-amazon-apigateway-request-validator": "Validate query string parameters and headers",
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.operator": "integration.response.body.op",
                "method.response.header.operand_2": "integration.response.body.b",
                "method.response.header.operand_1": "integration.response.body.a"
              },
              "responseTemplates": {
                "application/json": "#set($res = $input.path('$'))\n{\n    \"result\": \"$res.a, $res.b, $res.op => $res.c\",\n  \"a\" : \"$res.a\",\n  \"b\" : \"$res.b\",\n  \"op\" : \"$res.op\",\n  \"c\" : \"$res.c\"\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST",
          "requestTemplates": {
            "application/json": "{\n    \"a\":  \"$input.params('operand1')\",\n    \"b\":  \"$input.params('operand2')\", \n    \"op\": \"$input.params('operator')\"   \n}"
          },
          "type": "aws"
        }
      },
      "post": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "in": "body",
            "name": "Input",
            "required": true,
            "schema": {
              "$ref": "#/definitions/Input"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            }
          }
        },
        "x-amazon-apigateway-request-validator": "Validate body",
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "default": {
              "statusCode": "200",
              "responseTemplates": {
                "application/json": "#set($inputRoot = $input.path('$'))\n{\n  \"a\" : $inputRoot.a,\n  \"b\" : $inputRoot.b,\n  \"op\" : $inputRoot.op,\n  \"c\" : $inputRoot.c\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_templates",
          "httpMethod": "POST",
          "type": "aws"
        }
      }
    },
    "/calc/{operand1}/{operand2}/{operator}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "operand2",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "operator",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "operand1",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "default": {
              "statusCode": "200",
              "responseTemplates": {
                "application/json": "#set($inputRoot = $input.path('$'))\n{\n  \"input\" : {\n    \"a\" : $inputRoot.a,\n    \"b\" : $inputRoot.b,\n    \"op\" : \"$inputRoot.op\"\n  },\n  \"output\" : {\n    \"c\" : $inputRoot.c\n  }\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_templates",
          "httpMethod": "POST",
          "requestTemplates": {
            "application/json": "{\n   \"a\": \"$input.params('operand1')\",\n   \"b\": \"$input.params('operand2')\",\n   \"op\": #if($input.params('operator')=='%2F')\"/\"#{else}\"$input.params('operator')\"#end\n   \n}"
          },
          "contentHandling": "CONVERT_TO_TEXT",
          "type": "aws"
        }
      }
    }
  },
  "definitions": {
    "Input": {
      "type": "object",
      "required": [
        "a",
        "b",
        "op"
      ],
      "properties": {
        "a": {
          "type": "number"
        },
        "b": {
          "type": "number"
        },
        "op": {
          "type": "string",
          "description": "binary op of ['+', 'add', '-', 'sub', '*', 'mul', '%2F', 'div']"
        }
      },
      "title": "Input"
    },
    "Output": {
      "type": "object",
      "properties": {
        "c": {
          "type": "number"
        }
      },
      "title": "Output"
    },
    "Result": {
      "type": "object",
      "properties": {
        "input": {
          "$ref": "#/definitions/Input"
        },
        "output": {
          "$ref": "#/definitions/Output"
        }
      },
      "title": "Result"
    }
  },
  "x-amazon-apigateway-request-validators": {
    "Validate body": {
      "validateRequestParameters": false,
      "validateRequestBody": true
    },
    "Validate query string parameters and headers": {
      "validateRequestParameters": true,
      "validateRequestBody": false
    }
  }
}
```

------

# Tutorial: Create a REST API as an Amazon S3 proxy
<a name="integrating-api-with-aws-services-s3"></a>

As an example to showcase using a REST API in API Gateway to proxy Amazon S3, this section describes how to create and configure a REST API to expose the following Amazon S3 operations: 
+ Expose GET on the API's root resource to [list all of the Amazon S3 buckets of a caller](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html).
+ Expose GET on a Folder resource to [view a list of all of the objects in an Amazon S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html).
+ Expose GET on a Folder/Item resource to [view or download an object from an Amazon S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html).

 You might want to import the sample API as an Amazon S3 proxy, as shown in [OpenAPI definitions of the sample API as an Amazon S3 proxy](api-as-s3-proxy-export-swagger-with-extensions.md). This sample contains more exposed methods. For instructions on how to import an API using the OpenAPI definition, see [Develop REST APIs using OpenAPI in API Gateway](api-gateway-import-api.md).

**Note**  
 To integrate your API Gateway API with Amazon S3, you must choose a region where both the API Gateway and Amazon S3 services are available. For region availability, see [Amazon API Gateway Endpoints and Quotas](https://docs.aws.amazon.com/general/latest/gr/apigateway.html). 

**Topics**
+ [

## Set up IAM permissions for the API to invoke Amazon S3 actions
](#api-as-s3-proxy-iam-permissions)
+ [

## Create API resources to represent Amazon S3 resources
](#api-as-s3-proxy-create-resources)
+ [

## Expose an API method to list the caller's Amazon S3 buckets
](#api-root-get-as-s3-get-service)
+ [

## Expose API methods to access an Amazon S3 bucket
](#api-folder-operations-as-s3-bucket-actions)
+ [

## Expose API methods to access an Amazon S3 object in a bucket
](#api-items-in-folder-as-s3-objects-in-bucket)
+ [

# OpenAPI definitions of the sample API as an Amazon S3 proxy
](api-as-s3-proxy-export-swagger-with-extensions.md)
+ [

# Call the API using a REST API client
](api-as-s3-proxy-test-using-postman.md)

## Set up IAM permissions for the API to invoke Amazon S3 actions
<a name="api-as-s3-proxy-iam-permissions"></a>

 To allow the API to invoke Amazon S3 actions, you must have the appropriate IAM policies attached to an IAM role. In this step, you create a new IAM role.

**To create the AWS service proxy execution role**

1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. Choose **Roles**.

1. Choose **Create role**.

1.  Choose **AWS service** under **Select type of trusted entity**, and then select **API Gateway** and select **Allows API Gateway to push logs to CloudWatch Logs**.

1.  Choose **Next**, and then choose **Next**.

1. For **Role name**, enter **APIGatewayS3ProxyPolicy**, and then choose **Create role**.

1. In the **Roles** list, choose the role you just created. You may need to scroll or use the search bar to find the role.

1. For the selected role, select the **Add permissions** tab.

1. Choose **Attach policies** from the dropdown list.

1. In the search bar, enter **AmazonS3FullAccess** and choose **Add permissions**. 
**Note**  
This tutorial uses a managed policy for simplicity. As a best practice, you should create your own IAM policy to grant the minimum permissions required. 

1. Note the newly created **Role ARN**, you will use it later.

## Create API resources to represent Amazon S3 resources
<a name="api-as-s3-proxy-create-resources"></a>

You use the API's root (`/`) resource as the container of an authenticated caller's Amazon S3 buckets. You also create a `Folder` and `Item` resources to represent a particular Amazon S3 bucket and a particular Amazon S3 object, respectively. The folder name and object key will be specified, in the form of path parameters as part of a request URL, by the caller. 

**Note**  
When accessing objects whose object key includes `/` or any other special character, the character needs to be URL encoded. For example, `test/test.txt` should be encoded to `test%2Ftest.txt`.

**To create an API resource that exposes the Amazon S3 service features**

1.  In the same AWS Region you created your Amazon S3 bucket, create an API named **MyS3**. This API's root resource (**/**) represents the Amazon S3 service. In this step, you create two additional resources **/\$1folder\$1** and **/\$1item\$1**.

1. Choose **Create resource**.

1. Keep **Proxy resource** turned off. 

1. For **Resource path**, select `/`.

1. For **Resource name**, enter **\$1folder\$1**.

1. Keep **CORS (Cross Origin Resource Sharing)** unchecked.

1. Choose **Create resource**.

1. Select the **/\$1folder\$1** resource, and then choose **Create resource**.

1. Use the previous steps to create a child resource of **/\$1folder\$1** named **\$1item\$1**.

   Your final API should look similar to the following:

      
![\[Create an API in API Gateway as an Amazon S3 proxy\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/aws_proxy_s3_create_api-resources_new_console.png)

## Expose an API method to list the caller's Amazon S3 buckets
<a name="api-root-get-as-s3-get-service"></a>

Getting the list of Amazon S3 buckets of the caller involves invoking the [GET Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html) action on Amazon S3. On the API's root resource, (**/**), create the GET method. Configure the GET method to integrate with the Amazon S3, as follows. 

**To create and initialize the API's `GET /` method**

1. Select the **/** resource, and then choose **Create method**. 

1. For method type, select **GET**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Amazon S3 bucket. 

1. For **AWS service**, select **Amazon Simple Storage Service**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, select **GET**.

1. For **Action type**, select **Use path override**.

   With path override, API Gateway forwards the client request to Amazon S3 as the corresponding [Amazon S3 REST API path-style request](https://docs.aws.amazon.com/AmazonS3/latest/userguide/RESTAPI.html), in which a Amazon S3 resource is expressed by the resource path of the `s3-host-name/bucket/key` pattern. API Gateway sets the `s3-host-name` and passes the client specified `bucket` and `key` from the client to Amazon S3.

1. For **Path override**, enter **/**.

1. For **Execution role**, enter the role ARN for **APIGatewayS3ProxyPolicy**.

1. Choose **Method request settings**.

   You use the method request settings to control who can call this method of your API.

1. For **Authorization**, from the dropdown menu, select `AWS_IAM`.

      
![\[Declare method response types\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/aws_proxy_s3_setup_method_request_authorization_new_console.png)

1. Choose **Create method**.

This setup integrates the frontend `GET https://your-api-host/stage/` request with the backend `GET https://your-s3-host/`.

 For your API to return successful responses and exceptions properly to the caller, you declare the 200, 400 and 500 responses in **Method response**. You use the default mapping for 200 responses so that backend responses of the status code not declared here will be returned to the caller as 200 ones. 

**To declare response types for the `GET /` method**

1.  On the **Method response** tab, under **Response 200**, choose **Edit**.

1. Choose **Add header** and do the following:

   1. For **Header name**, enter **Content-Type**.

   1. Choose **Add header**.

   Repeat these steps to create a **Timestamp** header and a **Content-Length** header.

1. Choose **Save**.

1. On the **Method response** tab, under **Method responses**, choose **Create response**.

1. For **HTTP status code**, enter **400**.

   You do not set any headers for this response.

1. Choose **Save**.

1. Repeat the following steps to create the 500 response.

   You do not set any headers for this response.

Because the successful integration response from Amazon S3 returns the bucket list as an XML payload and the default method response from API Gateway returns a JSON payload, you must map the backend Content-Type header parameter value to the frontend counterpart. Otherwise, the client will receive `application/json` for the content type when the response body is actually an XML string. The following procedure shows how to set this up. In addition, you also want to display to the client other header parameters, such as Date and Content-Length. 

**To set up response header mappings for the GET / method**

1. On the **Integration response** tab, under **Default - Response**, choose **Edit**.

1. For the **Content-Length** header, enter **integration.response.header.Content-Length** for the mapping value.

1. For the **Content-Type** header, enter **integration.response.header.Content-Type** for the mapping value.

1. For the **Timestamp** header, enter **integration.response.header.Date** for the mapping value.

1. Choose **Save**. The result should look similar to the following:

      
![\[Map integration response headers to method response headers\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/aws_proxy_s3_setup_integration_response_headers_new_console.png)

1. On the **Integration response** tab, under **Integration responses**, choose **Create response**.

1. For **HTTP status regex**, enter **4\$1d\$12\$1**. This maps all 4xx HTTP response status codes to the method response.

1. For **Method response status code**, select **400**.

1. Choose **Create**.

1. Repeat the following steps to create an integration response for the 500 method response. For **HTTP status regex**, enter **5\$1d\$12\$1**.

As a good practice, you can test the API you have configured so far.

**To test the `GET /` method**

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. Choose **Test**. The result should look like the following image:

      
![\[Test API root GET bucket result\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/aws_proxy_s3_test_root_get_result_new_console.png)

## Expose API methods to access an Amazon S3 bucket
<a name="api-folder-operations-as-s3-bucket-actions"></a>

To work with an Amazon S3 bucket, you expose the `GET` method on the /\$1folder\$1 resource to list objects in a bucket. The instructions are similar to those described in [Expose an API method to list the caller's Amazon S3 buckets](#api-root-get-as-s3-get-service). For more methods, you can import the sample API here, [OpenAPI definitions of the sample API as an Amazon S3 proxy](api-as-s3-proxy-export-swagger-with-extensions.md).

**To expose the GET method on a folder resource**

1. Select the **/\$1folder\$1** resource, and then choose **Create method**. 

1. For method type, select **GET**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Amazon S3 bucket. 

1. For **AWS service**, select **Amazon Simple Storage Service**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, select **GET**.

1. For **Action type**, select **Use path override**.

1. For **Path override**, enter **\$1bucket\$1**.

1. For **Execution role**, enter the role ARN for **APIGatewayS3ProxyPolicy**.

1. Choose **Create method**.

You set the `{folder}` path parameter in the Amazon S3 endpoint URL. You need to map the `{folder}` path parameter of the method request to the `{bucket}` path parameter of the integration request.

**To map `{folder}` to `{bucket}`**

1.  On the **Integration request** tab, under **Integration request settings**, choose **Edit**. 

1. Choose **URL path parameters**, and then choose **Add path parameter**.

1. For **Name**, enter **bucket**.

1. For **Mapped from**, enter **method.request.path.folder**.

1. Choose **Save**.

Now, you test your API. 

**To test the `/{folder} GET` method.**

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. Under **Path**, for **folder**, enter the name of your bucket.

1. Choose **Test**.

   The test result will contain a list of object in your bucket.

      
![\[Test the GET method to create an Amazon S3 bucket.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/aws_proxy_s3_test_api_folder_get_new_console.png)

## Expose API methods to access an Amazon S3 object in a bucket
<a name="api-items-in-folder-as-s3-objects-in-bucket"></a>

Amazon S3 supports GET, DELETE, HEAD, OPTIONS, POST and PUT actions to access and manage objects in a given bucket. In this tutorial, you expose a `GET` method on the `{folder}/{item}` resource to get an image from a bucket. For more applications of the `{folder}/{item}` resource, see the sample API, [OpenAPI definitions of the sample API as an Amazon S3 proxy](api-as-s3-proxy-export-swagger-with-extensions.md).

**To expose the GET method on a item resource**

1. Select the **/\$1item\$1** resource, and then choose **Create method**. 

1. For method type, select **GET**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Amazon S3 bucket. 

1. For **AWS service**, select **Amazon Simple Storage Service**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, select **GET**.

1. For **Action type**, select **Use path override**.

1. For **Path override**, enter **\$1bucket\$1/\$1object\$1**.

1. For **Execution role**, enter the role ARN for **APIGatewayS3ProxyPolicy**.

1. Choose **Create method**.

You set the `{folder}` and `{item}` path parameters in the Amazon S3 endpoint URL. You need to map the path parameter of the method request to the path parameter of the integration request.

In this step, you do the following:
+ Map the `{folder}` path parameter of the method request to the `{bucket}` path parameter of the integration request.
+ Map the `{item}` path parameter of the method request to the `{object}` path parameter of the integration request.

**To map `{folder}` to `{bucket}` and `{item}` to `{object}`**

1.  On the **Integration request** tab, under **Integration request settings**, choose **Edit**. 

1. Choose **URL path parameters**.

1. Choose **Add path parameter**.

1. For **Name**, enter **bucket**.

1. For **Mapped from**, enter **method.request.path.folder**.

1. Choose **Add path parameter**.

1. For **Name**, enter **object**.

1. For **Mapped from**, enter **method.request.path.item**.

1. Choose **Save**.

**To test the `/{folder}/{object} GET` method.**

1. Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

1. Under **Path**, for **folder**, enter the name of your bucket.

1. Under **Path**, for **item**, enter the name of an item.

1. Choose **Test**.

   The response body will contain the contents of the item.

      
![\[Test the GET method to create an Amazon S3 bucket.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/aws_proxy_s3_test_api_item_get_new_console.png)

   The request correctly returns the plain text of ("Hello world") as the content of the specified file (test.txt) in the given Amazon S3 bucket (amzn-s3-demo-bucket).

 To download or upload binary files, which in API Gateway is considered any thing other than utf-8 encoded JSON content, additional API settings are necessary. This is outlined as follows: 

**To download or upload binary files from S3**

1.  Register the media types of the affected file to the API's binaryMediaTypes. You can do this in the console: 

   1. Choose **API settings** for the API.

   1. Under **Binary media types**, choose **Manage media types**.

   1. Choose **Add binary media type**, and then enter the required media type, for example, `image/png`.

   1. Choose **Save changes** to save the setting.

1. Add the `Content-Type` (for upload) and/or `Accept` (for download) header to the method request to require the client to specify the required binary media type and map them to the integration request.

1. Set **Content Handling** to `Passthrough` in the integration request (for upload) and in a integration response (for download). Make sure that no mapping template is defined for the affected content type. For more information, see [Data transformations for REST APIs in API Gateway](rest-api-data-transformations.md).

The payload size limit is 10 MB. See [Quotas for configuring and running a REST API in API Gateway](api-gateway-execution-service-limits-table.md).

Make sure that files on Amazon S3 have the correct content types added as the files' metadata. For streamable media content, `Content-Disposition:inline` may also need to be added to the metadata.

For more information about the binary support in API Gateway, see [Content type conversions in API Gateway](api-gateway-payload-encodings-workflow.md).

# OpenAPI definitions of the sample API as an Amazon S3 proxy
<a name="api-as-s3-proxy-export-swagger-with-extensions"></a>

The following OpenAPI definitions describes an API that works as an Amazon S3 proxy. This API contains more Amazon S3 operations than the API you created in the tutorial. The following methods are exposed in the OpenAPI definitions:
+ Expose GET on the API's root resource to [list all of the Amazon S3 buckets of a caller](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html).
+ Expose GET on a Folder resource to [view a list of all of the objects in an Amazon S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html).
+ Expose PUT on a Folder resource to [add a bucket to Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html).
+ Expose DELETE on a Folder resource to [remove a bucket from Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html).
+ Expose GET on a Folder/Item resource to [view or download an object from an Amazon S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html).
+ Expose PUT on a Folder/Item resource to [upload an object to an Amazon S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html).
+ Expose HEAD on a Folder/Item resource to [get object metadata in an Amazon S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html).
+ Expose DELETE on a Folder/Item resource to [remove an object from an Amazon S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html).

For instructions on how to import an API using the OpenAPI definition, see [Develop REST APIs using OpenAPI in API Gateway](api-gateway-import-api.md).

For instructions on how to create a similar API, see [Tutorial: Create a REST API as an Amazon S3 proxy](integrating-api-with-aws-services-s3.md).

To learn how to invoke this API using [Postman](https://www.postman.com/), which supports the AWS IAM authorization, see [Call the API using a REST API client](api-as-s3-proxy-test-using-postman.md).

------
#### [ OpenAPI 2.0 ]

```
{
  "swagger": "2.0",
  "info": {
    "version": "2016-10-13T23:04:43Z",
    "title": "MyS3"
  },
  "host": "9gn28ca086.execute-api.{region}.amazonaws.com",
  "basePath": "/S3",
  "schemes": [
    "https"
  ],
  "paths": {
    "/": {
      "get": {
        "produces": [
          "application/json"
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Timestamp": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Content-Length": "integration.response.header.Content-Length",
                "method.response.header.Timestamp": "integration.response.header.Date"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path//",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "GET",
          "type": "aws"
        }
      }
    },
    "/{folder}": {
      "get": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Date": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Date": "integration.response.header.Date",
                "method.response.header.Content-Length": "integration.response.header.content-length"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.bucket": "method.request.path.folder"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "GET",
          "type": "aws"
        }
      },
      "put": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "required": false,
            "type": "string"
          },
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Content-Length": "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.bucket": "method.request.path.folder",
            "integration.request.header.Content-Type": "method.request.header.Content-Type"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "PUT",
          "type": "aws"
        }
      },
      "delete": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Date": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Date": "integration.response.header.Date"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.bucket": "method.request.path.folder"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "DELETE",
          "type": "aws"
        }
      }
    },
    "/{folder}/{item}": {
      "get": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "item",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "content-type": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.content-type": "integration.response.header.content-type",
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.object": "method.request.path.item",
            "integration.request.path.bucket": "method.request.path.folder"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "GET",
          "type": "aws"
        }
      },
      "head": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "item",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Content-Length": "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.object": "method.request.path.item",
            "integration.request.path.bucket": "method.request.path.folder"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "HEAD",
          "type": "aws"
        }
      },
      "put": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "required": false,
            "type": "string"
          },
          {
            "name": "item",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Content-Length": "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.object": "method.request.path.item",
            "integration.request.path.bucket": "method.request.path.folder",
            "integration.request.header.Content-Type": "method.request.header.Content-Type"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "PUT",
          "type": "aws"
        }
      },
      "delete": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "item",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200"
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.object": "method.request.path.item",
            "integration.request.path.bucket": "method.request.path.folder"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "DELETE",
          "type": "aws"
        }
      }
    }
  },
  "securityDefinitions": {
    "sigv4": {
      "type": "apiKey",
      "name": "Authorization",
      "in": "header",
      "x-amazon-apigateway-authtype": "awsSigv4"
    }
  },
  "definitions": {
    "Empty": {
      "type": "object",
      "title": "Empty Schema"
    }
  }
}
```

------
#### [ OpenAPI 3.0 ]

```
{
  "openapi" : "3.0.1",
  "info" : {
    "title" : "MyS3",
    "version" : "2016-10-13T23:04:43Z"
  },
  "servers" : [ {
    "url" : "https://9gn28ca086.execute-api.{region}.amazonaws.com/{basePath}",
    "variables" : {
      "basePath" : {
        "default" : "S3"
      }
    }
  } ],
  "paths" : {
    "/{folder}" : {
      "get" : {
        "parameters" : [ {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Date" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "GET",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Date" : "integration.response.header.Date",
                "method.response.header.Content-Length" : "integration.response.header.content-length"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.bucket" : "method.request.path.folder"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      },
      "put" : {
        "parameters" : [ {
          "name" : "Content-Type",
          "in" : "header",
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "PUT",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Content-Length" : "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.bucket" : "method.request.path.folder",
            "integration.request.header.Content-Type" : "method.request.header.Content-Type"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      },
      "delete" : {
        "parameters" : [ {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Date" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "DELETE",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Date" : "integration.response.header.Date"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.bucket" : "method.request.path.folder"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      }
    },
    "/{folder}/{item}" : {
      "get" : {
        "parameters" : [ {
          "name" : "item",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "content-type" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "GET",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.content-type" : "integration.response.header.content-type",
                "method.response.header.Content-Type" : "integration.response.header.Content-Type"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.object" : "method.request.path.item",
            "integration.request.path.bucket" : "method.request.path.folder"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      },
      "put" : {
        "parameters" : [ {
          "name" : "Content-Type",
          "in" : "header",
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "item",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "PUT",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Content-Length" : "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.object" : "method.request.path.item",
            "integration.request.path.bucket" : "method.request.path.folder",
            "integration.request.header.Content-Type" : "method.request.header.Content-Type"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      },
      "delete" : {
        "parameters" : [ {
          "name" : "item",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "DELETE",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200"
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.object" : "method.request.path.item",
            "integration.request.path.bucket" : "method.request.path.folder"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      },
      "head" : {
        "parameters" : [ {
          "name" : "item",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "HEAD",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Content-Length" : "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.object" : "method.request.path.item",
            "integration.request.path.bucket" : "method.request.path.folder"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      }
    },
    "/" : {
      "get" : {
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Timestamp" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "GET",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path//",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Content-Length" : "integration.response.header.Content-Length",
                "method.response.header.Timestamp" : "integration.response.header.Date"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      }
    }
  },
  "components" : {
    "schemas" : {
      "Empty" : {
        "title" : "Empty Schema",
        "type" : "object"
      }
    }
  }
}
```

------

# Call the API using a REST API client
<a name="api-as-s3-proxy-test-using-postman"></a>

To provide an end-to-end tutorial, we now show how to call the API using [Postman](https://www.postman.com/), which supports the AWS IAM authorization.<a name="api-as-s3-proxy-test-using-postman-steps"></a>

**To call our Amazon S3 proxy API using Postman**

1. Deploy or redeploy the API. Make a note of the base URL of the API that is displayed next to **Invoke URL** at the top of the **Stage Editor**.

1. Launch Postman.

1. Choose **Authorization** and then choose `AWS Signature`. Enter your IAM user's Access Key ID and Secret Access Key into the **AccessKey** and **SecretKey**input fields, respectively. Enter the AWS Region to which your API is deployed in the **AWS Region** text box. Enter `execute-api` in the **Service Name** input field.

   You can create a pair of the keys from the **Security Credentials** tab from your IAM user account in the IAM Management Console.

1. To add a bucket named `amzn-s3-demo-bucket` to your Amazon S3 account in the `{region}` region:

   1. Choose **PUT** from the drop-down method list and type the method URL (`https://api-id.execute-api.aws-region.amazonaws.com/stage/folder-name`

   1. Set the `Content-Type` header value as `application/xml`. You may need to delete any existing headers before setting the content type.

   1. Choose **Body** menu item and type the following XML fragment as the request body:

      ```
      <CreateBucketConfiguration> 
        <LocationConstraint>{region}</LocationConstraint> 
      </CreateBucketConfiguration>
      ```

   1. Choose **Send** to submit the request. If successful, you should receive a `200 OK` response with an empty payload. 

1. To add a text file to a bucket, follow the instructions above. If you specify a bucket name of **amzn-s3-demo-bucket** for `{folder}` and a file name of **Readme.txt** for `{item}` in the URL and provide a text string of **Hello, World\$1** as the file contents (thereby making it the request payload), the request becomes

   ```
   PUT /S3/amzn-s3-demo-bucket/Readme.txt HTTP/1.1
   Host: 9gn28ca086.execute-api.{region}.amazonaws.com
   Content-Type: application/xml
   X-Amz-Date: 20161015T062647Z
   Authorization: AWS4-HMAC-SHA256 Credential=access-key-id/20161015/{region}/execute-api/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date, Signature=ccadb877bdb0d395ca38cc47e18a0d76bb5eaf17007d11e40bf6fb63d28c705b
   Cache-Control: no-cache
   Postman-Token: 6135d315-9cc4-8af8-1757-90871d00847e
   
   Hello, World!
   ```

   If everything goes well, you should receive a `200 OK` response with an empty payload.

1. To get the content of the `Readme.txt` file we just added to the `amzn-s3-demo-bucket` bucket, do a GET request like the following one:

   ```
   GET /S3/amzn-s3-demo-bucket/Readme.txt HTTP/1.1
   Host: 9gn28ca086.execute-api.{region}.amazonaws.com
   Content-Type: application/xml
   X-Amz-Date: 20161015T063759Z
   Authorization: AWS4-HMAC-SHA256 Credential=access-key-id/20161015/{region}/execute-api/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=ba09b72b585acf0e578e6ad02555c00e24b420b59025bc7bb8d3f7aed1471339
   Cache-Control: no-cache
   Postman-Token: d60fcb59-d335-52f7-0025-5bd96928098a
   ```

   If successful, you should receive a `200 OK` response with the `Hello, World!` text string as the payload.

1. To list items in the `amzn-s3-demo-bucket` bucket, submit the following request:

   ```
   GET /S3/amzn-s3-demo-bucket HTTP/1.1
   Host: 9gn28ca086.execute-api.{region}.amazonaws.com
   Content-Type: application/xml
   X-Amz-Date: 20161015T064324Z
   Authorization: AWS4-HMAC-SHA256 Credential=access-key-id/20161015/{region}/execute-api/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=4ac9bd4574a14e01568134fd16814534d9951649d3a22b3b0db9f1f5cd4dd0ac
   Cache-Control: no-cache
   Postman-Token: 9c43020a-966f-61e1-81af-4c49ad8d1392
   ```

   If successful, you should receive a `200 OK` response with an XML payload showing a single item in the specified bucket, unless you added more files to the bucket before submitting this request.

   ```
   <?xml version="1.0" encoding="UTF-8"?>
   <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
       <Name>apig-demo-5</Name>
       <Prefix></Prefix>
       <Marker></Marker>
       <MaxKeys>1000</MaxKeys>
       <IsTruncated>false</IsTruncated>
       <Contents>
           <Key>Readme.txt</Key>
           <LastModified>2016-10-15T06:26:48.000Z</LastModified>
           <ETag>"65a8e27d8879283831b664bd8b7f0ad4"</ETag>
           <Size>13</Size>
           <Owner>
               <ID>06e4b09e9d...603addd12ee</ID>
               <DisplayName>user-name</DisplayName>
           </Owner>
           <StorageClass>STANDARD</StorageClass>
       </Contents>
   </ListBucketResult>
   ```

**Note**  
To upload or download an image, you need to set content handling to CONVERT\$1TO\$1BINARY.

# Tutorial: Create a REST API as an Amazon Kinesis proxy
<a name="integrating-api-with-aws-services-kinesis"></a>

This page describes how to create and configure a REST API with an integration of the `AWS` type to access Kinesis. 

**Note**  
 To integrate your API Gateway API with Kinesis, you must choose a region where both the API Gateway and Kinesis services are available. For region availability, see [Service Endpoints and Quotas](https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html).

 For the purpose of illustration, we create an example API to enable a client to do the following: 

1. List the user's available streams in Kinesis 

1. Create, describe, or delete a specified stream

1. Read data records from or write data records into the specified stream

 To accomplish the preceding tasks, the API exposes methods on various resources to invoke the following, respectively: 

1. The `ListStreams` action in Kinesis 

1. The `CreateStream`, `DescribeStream`, or `DeleteStream` action

1. The `GetRecords` or `PutRecords` (including `PutRecord`) action in Kinesis

 Specifically, we build the API as follows: 
+  Expose an HTTP GET method on the API's `/streams` resource and integrate the method with the [ListStreams](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_ListStreams.html) action in Kinesis to list the streams in the caller's account. 
+  Expose an HTTP POST method on the API's `/streams/{stream-name}` resource and integrate the method with the [CreateStream](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_CreateStream.html) action in Kinesis to create a named stream in the caller's account. 
+  Expose an HTTP GET method on the API's `/streams/{stream-name}` resource and integrate the method with the [DescribeStream](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_DescribeStream.html) action in Kinesis to describe a named stream in the caller's account. 
+  Expose an HTTP DELETE method on the API's `/streams/{stream-name}` resource and integrate the method with the [DeleteStream](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_DeleteStream.html) action in Kinesis to delete a stream in the caller's account. 
+  Expose an HTTP PUT method on the API's `/streams/{stream-name}/record` resource and integrate the method with the [PutRecord](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecord.html) action in Kinesis. This enables the client to add a single data record to the named stream. 
+  Expose an HTTP PUT method on the API's `/streams/{stream-name}/records` resource and integrate the method with the [PutRecords](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecords.html) action in Kinesis. This enables the client to add a list of data records to the named stream. 
+  Expose an HTTP GET method on the API's `/streams/{stream-name}/records` resource and integrate the method with the [GetRecords](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetRecords.html) action in Kinesis. This enables the client to list data records in the named stream, with a specified shard iterator. A shard iterator specifies the shard position from which to start reading data records sequentially.
+  Expose an HTTP GET method on the API's `/streams/{stream-name}/sharditerator` resource and integrate the method with the [GetShardIterator](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html) action in Kinesis. This helper method must be supplied to the `ListStreams` action in Kinesis. 

 You can apply the instructions presented here to other Kinesis actions. For the complete list of the Kinesis actions, see [Amazon Kinesis API Reference](https://docs.aws.amazon.com/kinesis/latest/APIReference/Welcome.html). 

 Instead of using the API Gateway console to create the sample API, you can import the sample API into API Gateway using the API Gateway [Import API](https://docs.aws.amazon.com/apigateway/latest/api/API_ImportRestApi.html). For information on how to use the Import API, see [Develop REST APIs using OpenAPI in API Gateway](api-gateway-import-api.md). 

## Create an IAM role and policy for the API to access Kinesis
<a name="integrate-with-kinesis-create-iam-role-and-policy"></a>

 To allow the API to invoke Kinesis actions, you must have the appropriate IAM policies attached to an IAM role. In this step, you create a new IAM role.

**To create the AWS service proxy execution role**

1. Sign in to the AWS Management Console and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. Choose **Roles**.

1. Choose **Create role**.

1.  Choose **AWS service** under **Select type of trusted entity**, and then select **API Gateway** and select **Allows API Gateway to push logs to CloudWatch Logs**.

1.  Choose **Next**, and then choose **Next**.

1. For **Role name**, enter **APIGatewayKinesisProxyPolicy**, and then choose **Create role**.

1. In the **Roles** list, choose the role you just created. You may need to scroll or use the search bar to find the role.

1. For the selected role, select the **Add permissions** tab.

1. Choose **Attach policies** from the dropdown list.

1. In the search bar, enter **AmazonKinesisFullAccess** and choose **Add permissions**. 
**Note**  
This tutorial uses a managed policy for simplicity. As a best practice, you should create your own IAM policy to grant the minimum permissions required. 

1. Note the newly created **Role ARN**, you will use it later.

## Create an API as a Kinesis proxy
<a name="api-gateway-create-api-as-kinesis-proxy"></a>

Use the following steps to create the API in the API Gateway console.

**To create an API as an AWS service proxy for Kinesis**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. If this is your first time using API Gateway, you see a page that introduces you to the features of the service. Under **REST API**, choose **Build**. When the **Create Example API** popup appears, choose **OK**.

   If this is not your first time using API Gateway, choose **Create API**. Under **REST API**, choose **Build**.

1. Choose **New API**. 

1. In **API name**, enter **KinesisProxy**. Keep the default values for all other fields. 

1. (Optional) For **Description**, enter a description.

1. For **IP address type**, select **IPv4**.

1. Choose **Create API**. 

 After the API is created, the API Gateway console displays the **Resources** page, which contains only the API's root (`/`) resource. 

## List streams in Kinesis
<a name="api-gateway-list-kinesis-streams"></a>

 Kinesis supports the `ListStreams` action with the following REST API call: 

```
POST /?Action=ListStreams HTTP/1.1
Host: kinesis.<region>.<domain>
Content-Length: <PayloadSizeBytes>
User-Agent: <UserAgentString>
Content-Type: application/x-amz-json-1.1
Authorization: <AuthParams>
X-Amz-Date: <Date>
        
{
   ...
}
```

In the above REST API request, the action is specified in the `Action` query parameter. Alternatively, you can specify the action in a `X-Amz-Target` header, instead:

```
POST / HTTP/1.1
Host: kinesis.<region>.<domain>
Content-Length: <PayloadSizeBytes>
User-Agent: <UserAgentString>
Content-Type: application/x-amz-json-1.1
Authorization: <AuthParams>
X-Amz-Date: <Date>
X-Amz-Target: Kinesis_20131202.ListStreams        
{
   ...
}
```

In this tutorial, we use the query parameter to specify action.

To expose a Kinesis action in the API, add a `/streams` resource to the API's root. Then set a `GET` method on the resource and integrate the method with the `ListStreams` action of Kinesis. 

The following procedure describes how to list Kinesis streams by using the API Gateway console. 

**To list Kinesis streams by using the API Gateway console**

1. Select the `/` resource, and then choose **Create resource**. 

1. For **Resource name**, enter **streams**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

1.  Choose the `/streams` resource, and then choose **Create method**, and then do the following:

   1. For **Method type**, select **GET**.
**Note**  
The HTTP verb for a method invoked by a client may differ from the HTTP verb for an integration required by the backend. We select `GET` here, because listing streams is intuitively a READ operation. 

   1. For **Integration type**, select **AWS service**.

   1. For **AWS Region**, select the AWS Region where you created your Kinesis stream. 

   1. For **AWS service**, select **Kinesis**.

   1. Keep **AWS subdomain** blank.

   1. For **HTTP method**, choose **POST**.
**Note**  
We chose `POST` here because Kinesis requires that the `ListStreams` action be invoked with it. 

   1. For **Action type**, choose **Use action name**.

   1. For **Action name**, enter **ListStreams**.

   1. For **Execution role**, enter the ARN for your execution role.

   1. Keep the default of **Passthrough** for **Content Handling**.

   1. Choose **Create method**.

1. On the **Integration request** tab, under **Integration request settings**, choose **Edit**. 

1. For **Request body passthrough**, select **When there are no templates defined (recommended)**.

1.  Choose **URL request headers parameters**, and then do the following:

   1. Choose **Add request headers parameter**.

   1. For **Name**, enter **Content-Type**.

   1. For **Mapped from**, enter **'application/x-amz-json-1.1'**.

    We use a request parameter mapping to set the `Content-Type` header to the static value of `'application/x-amz-json-1.1'` to inform Kinesis that the input is of a specific version of JSON. 

1. Choose **Mapping templates**, and then choose **Add mapping template**, and do the following:

   1. For **Content-Type**, enter **application/json**.

   1. For **Template body**, enter **\$1\$1**.

   1. Choose **Save**.

    The [ListStreams](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_ListStreams.html#API_ListStreams_RequestSyntax) request takes a payload of the following JSON format: 

   ```
   {
       "ExclusiveStartStreamName": "string",
       "Limit": number
   }
   ```

   However, the properties are optional. To use the default values, we opted for an empty JSON payload here.

1. Test the GET method on the **/streams** resource to invoke the `ListStreams` action in Kinesis:

   Choose the **Test** tab. You might need to choose the right arrow button to show the tab.

   Choose **Test** to test your method.

    If you already created two streams named "myStream" and "yourStream" in Kinesis, the successful test returns a 200 OK response containing the following payload: 

   ```
   {
        "HasMoreStreams": false,
        "StreamNames": [
            "myStream",
            "yourStream"
        ]
   }
   ```

## Create, describe, and delete a stream in Kinesis
<a name="api-gateway-create-describe-delete-stream"></a>

 Creating, describing, and deleting a stream in Kinesis involves making the following Kinesis REST API requests, respectively: 

```
POST /?Action=CreateStream HTTP/1.1
Host: kinesis.region.domain
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "ShardCount": number,
    "StreamName": "string"
}
```

```
POST /?Action=DescribeStream HTTP/1.1
Host: kinesis.region.domain
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "StreamName": "string"
}
```

```
POST /?Action=DeleteStream HTTP/1.1
Host: kinesis.region.domain
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "StreamName":"string"
}
```

 We can build the API to accept the required input as a JSON payload of the method request and pass the payload through to the integration request. However, to provide more examples of data mapping between method and integration requests, and method and integration responses, we create our API somewhat differently. 

 We expose the `GET`, `POST`, and `Delete` HTTP methods on a to-be-named `Stream` resource. We use the `{stream-name}` path variable as the placeholder of the stream resource and integrate these API methods with the Kinesis' `DescribeStream`, `CreateStream`, and `DeleteStream` actions, respectively. We require that the client pass other input data as headers, query parameters, or the payload of a method request. We provide mapping templates to transform the data to the required integration request payload. 

**To create the \$1stream-name\$1 resource**

1. Choose the **/streams** resource, and then choose **Create resource**.

1. Keep **Proxy resource** turned off. 

1. For **Resource path**, select `/streams`.

1. For **Resource name**, enter **\$1stream-name\$1**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

**To configure and test the GET method on a stream resource**

1. Choose the **/\$1stream-name\$1** resource, and then choose **Create method**.

1. For **Method type**, select **GET**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Kinesis stream. 

1. For **AWS service**, select **Kinesis**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, choose **POST**.

1. For **Action type**, choose **Use action name**.

1. For **Action name**, enter **DescribeStream**.

1. For **Execution role**, enter the ARN for your execution role.

1. Keep the default of **Passthrough** for **Content Handling**.

1. Choose **Create method**.

1. In the **Integration request** section, add the following **URL request headers parameters**:

   ```
   Content-Type: 'x-amz-json-1.1'
   ```

   The task follows the same procedure to set up the request parameter mapping for the `GET /streams` method.

1. Add the following body mapping template to map data from the `GET /streams/{stream-name}` method request to the `POST /?Action=DescribeStream` integration request:

   ```
   {
       "StreamName": "$input.params('stream-name')"
   }
   ```

   This mapping template generates the required integration request payload for the `DescribeStream` action of Kinesis from the method request's `stream-name` path parameter value.

1. To test the `GET /stream/{stream-name}` method to invoke the `DescribeStream` action in Kinesis, choose the **Test** tab.

1. For **Path**, under **stream-name**, enter the name of an existing Kinesis stream.

1. Choose **Test**. If the test is successful, a 200 OK response is returned with a payload similar to the following: 

   ```
   {
     "StreamDescription": {
       "HasMoreShards": false,
       "RetentionPeriodHours": 24,
       "Shards": [
         {
           "HashKeyRange": {
             "EndingHashKey": "68056473384187692692674921486353642290",
             "StartingHashKey": "0"
           },
           "SequenceNumberRange": {
             "StartingSequenceNumber": "49559266461454070523309915164834022007924120923395850242"
           },
           "ShardId": "shardId-000000000000"
         },
         ...
         {
           "HashKeyRange": {
             "EndingHashKey": "340282366920938463463374607431768211455",
             "StartingHashKey": "272225893536750770770699685945414569164"
           },
           "SequenceNumberRange": {
             "StartingSequenceNumber": "49559266461543273504104037657400164881014714369419771970"
           },
           "ShardId": "shardId-000000000004"
         }
       ],
       "StreamARN": "arn:aws:kinesis:us-east-1:12345678901:stream/myStream",
       "StreamName": "myStream",
       "StreamStatus": "ACTIVE"
     }
   }
   ```

    After you deploy the API, you can make a REST request against this API method: 

   ```
   GET https://your-api-id.execute-api.region.amazonaws.com/stage/streams/myStream HTTP/1.1
   Host: your-api-id.execute-api.region.amazonaws.com
   Content-Type: application/json
   Authorization: ...
   X-Amz-Date: 20160323T194451Z
   ```

**To configure and test the POST method on a stream resource**

1. Choose the **/\$1stream-name\$1** resource, and then choose **Create method**.

1. For **Method type**, select **POST**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Kinesis stream. 

1. For **AWS service**, select **Kinesis**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, choose **POST**.

1. For **Action type**, choose **Use action name**.

1. For **Action name**, enter **CreateStream**.

1. For **Execution role**, enter the ARN for your execution role.

1. Keep the default of **Passthrough** for **Content Handling**.

1. Choose **Create method**.

1. In the **Integration request** section, add the following **URL request headers parameters**:

   ```
   Content-Type: 'x-amz-json-1.1'
   ```

   The task follows the same procedure to set up the request parameter mapping for the `GET /streams` method.

1.  Add the following body mapping template to map data from the `POST /streams/{stream-name}` method request to the `POST /?Action=CreateStream` integration request: 

   ```
   {
       "ShardCount": #if($input.path('$.ShardCount') == '') 5 #else $input.path('$.ShardCount') #end,
       "StreamName": "$input.params('stream-name')"
   }
   ```

    In the preceding mapping template, we set `ShardCount` to a fixed value of 5 if the client does not specify a value in the method request payload. 

1. To test the `POST /stream/{stream-name}` method to invoke the `CreateStream` action in Kinesis, choose the **Test** tab.

1. For **Path**, under **stream-name**, enter the name of a new Kinesis stream.

1. Choose **Test**. If the test is successful, a 200 OK response is returned with no data. 

    After you deploy the API, you can also make a REST API request against the POST method on a Stream resource to invoke the `CreateStream` action in Kinesis: 

   ```
   POST https://your-api-id.execute-api.region.amazonaws.com/stage/streams/yourStream HTTP/1.1
   Host: your-api-id.execute-api.region.amazonaws.com
   Content-Type: application/json
   Authorization: ...
   X-Amz-Date: 20160323T194451Z
   
   { 
       "ShardCount": 5
   }
   ```

**Configure and test the DELETE method on a stream resource**

1. Choose the **/\$1stream-name\$1** resource, and then choose **Create method**.

1. For **Method type**, select **DELETE**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Kinesis stream. 

1. For **AWS service**, select **Kinesis**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, choose **POST**.

1. For **Action type**, choose **Use action name**.

1. For **Action name**, enter **DeleteStream**.

1. For **Execution role**, enter the ARN for your execution role.

1. Keep the default of **Passthrough** for **Content Handling**.

1. Choose **Create method**.

1. In the **Integration request** section, add the following **URL request headers parameters**:

   ```
   Content-Type: 'x-amz-json-1.1'
   ```

   The task follows the same procedure to set up the request parameter mapping for the `GET /streams` method.

1.  Add the following body mapping template to map data from the `DELETE /streams/{stream-name}` method request to the corresponding integration request of `POST /?Action=DeleteStream` : 

   ```
   {
       "StreamName": "$input.params('stream-name')"
   }
   ```

    This mapping template generates the required input for the `DELETE /streams/{stream-name}` action from the client-supplied URL path name of `stream-name`. 

1. To test the `DELETE /stream/{stream-name}` method to invoke the `DeleteStream` action in Kinesis, choose the **Test** tab.

1. For **Path**, under **stream-name**, enter the name of an existing Kinesis stream.

1. Choose **Test**. If the test is successful, a 200 OK response is returned with no data. 

    After you deploy the API, you can also make the following REST API request against the DELETE method on the Stream resource to call the `DeleteStream` action in Kinesis: 

   ```
   DELETE https://your-api-id.execute-api.region.amazonaws.com/stage/streams/yourStream HTTP/1.1
   Host: your-api-id.execute-api.region.amazonaws.com
   Content-Type: application/json
   Authorization: ...
   X-Amz-Date: 20160323T194451Z
   
   {}
   ```

## Get records from and add records to a stream in Kinesis
<a name="api-gateway-get-and-add-records-to-stream"></a>

 After you create a stream in Kinesis, you can add data records to the stream and read the data from the stream. Adding data records involves calling the [PutRecords](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecords.html#API_PutRecords_Examples) or [PutRecord](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecord.html#API_PutRecord_Examples) action in Kinesis. The former adds multiple records whereas the latter adds a single record to the stream. 

```
POST /?Action=PutRecords HTTP/1.1
Host: kinesis.region.domain
Authorization: AWS4-HMAC-SHA256 Credential=..., ...
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "Records": [
        {
            "Data": blob,
            "ExplicitHashKey": "string",
            "PartitionKey": "string"
        }
    ],
    "StreamName": "string"
}
```

or

```
POST /?Action=PutRecord HTTP/1.1
Host: kinesis.region.domain
Authorization: AWS4-HMAC-SHA256 Credential=..., ...
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "Data": blob,
    "ExplicitHashKey": "string",
    "PartitionKey": "string",
    "SequenceNumberForOrdering": "string",
    "StreamName": "string"
}
```

 Here, `StreamName` identifies the target stream to add records. `StreamName`, `Data`, and `PartitionKey` are required input data. In our example, we use the default values for all of the optional input data and will not explicitly specify values for them in the input to the method request. 

 Reading data in Kinesis amounts to calling the [GetRecords](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetRecords.html#API_GetRecords_Examples) action: 

```
POST /?Action=GetRecords HTTP/1.1
Host: kinesis.region.domain
Authorization: AWS4-HMAC-SHA256 Credential=..., ...
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "ShardIterator": "string",
    "Limit": number
}
```

Here, the source stream from which we are getting records is specified in the required `ShardIterator` value, as is shown in the following Kinesis action to obtain a shard iterator:

```
POST /?Action=GetShardIterator HTTP/1.1
Host: kinesis.region.domain
Authorization: AWS4-HMAC-SHA256 Credential=..., ...
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes
                
{
    "ShardId": "string",
    "ShardIteratorType": "string",
    "StartingSequenceNumber": "string",
    "StreamName": "string"
}
```

 For the `GetRecords` and `PutRecords` actions, we expose the `GET` and `PUT` methods, respectively, on a `/records` resource that is appended to a named stream resource (`/{stream-name}`). Similarly, we expose the `PutRecord` action as a `PUT` method on a `/record` resource. 

 Because the `GetRecords` action takes as input a `ShardIterator` value, which is obtained by calling the `GetShardIterator` helper action, we expose a `GET` helper method on a `ShardIterator` resource (`/sharditerator`). 

**To create the /record, /records, and /sharditerator resources**

1. Choose the **/\$1stream-name\$1** resource, and then choose **Create resource**.

1. Keep **Proxy resource** turned off. 

1. For **Resource path**, select `/{stream-name}`.

1. For **Resource name**, enter **record**.

1. Keep **CORS (Cross Origin Resource Sharing)** turned off.

1. Choose **Create resource**.

1. Repeat the previous steps to create a **/records** and a **/sharditerator** resource. The final API should look like the following:

      
![\[Create Records:GET|PUT|PUT|GET method for the API.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/api-gateway-kinesis-proxy-setup-streams-stream-record-method-new-console.png)

 The following four procedures describe how to set up each of the methods, how to map data from the method requests to the integration requests, and how to test the methods. 

**To set up and test the `PUT /streams/{stream-name}/record` method to invoke `PutRecord` in Kinesis:**

1. Choose the **/record**, and then choose **Create method**.

1. For **Method type**, select **PUT**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Kinesis stream. 

1. For **AWS service**, select **Kinesis**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, choose **POST**.

1. For **Action type**, choose **Use action name**.

1. For **Action name**, enter **PutRecord**.

1. For **Execution role**, enter the ARN for your execution role.

1. Keep the default of **Passthrough** for **Content Handling**.

1. Choose **Create method**.

1. In the **Integration request** section, add the following **URL request headers parameters**:

   ```
   Content-Type: 'x-amz-json-1.1'
   ```

   The task follows the same procedure to set up the request parameter mapping for the `GET /streams` method.

1.  Add the following body mapping template to map data from the `PUT /streams/{stream-name}/record` method request to the corresponding integration request of `POST /?Action=PutRecord`: 

   ```
   {
       "StreamName": "$input.params('stream-name')",
       "Data": "$util.base64Encode($input.json('$.Data'))",
       "PartitionKey": "$input.path('$.PartitionKey')"
   }
   ```

    This mapping template assumes that the method request payload is of the following format: 

   ```
   {
      "Data": "some data",
      "PartitionKey": "some key"
   }
   ```

   This data can be modeled by the following JSON schema:

   ```
   {
     "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "PutRecord proxy single-record payload",
     "type": "object",
     "properties": {
         "Data": { "type": "string" },
         "PartitionKey": { "type": "string" }
     }
   }
   ```

    You can create a model to include this schema and use the model to facilitate generating the mapping template. However, you can generate a mapping template without using any model. 

1.  To test the `PUT /streams/{stream-name}/record` method, set the `stream-name` path variable to the name of an existing stream, supply a payload of the required format, and then submit the method request. The successful result is a `200 OK `response with a payload of the following format: 

   ```
   {
     "SequenceNumber": "49559409944537880850133345460169886593573102115167928386",
     "ShardId": "shardId-000000000004"
   }
   ```

**To set up and test the `PUT /streams/{stream-name}/records` method to invoke `PutRecords` in Kinesis**

1. Choose the **/records** resource, and then choose **Create method**.

1. For **Method type**, select **PUT**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Kinesis stream. 

1. For **AWS service**, select **Kinesis**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, choose **POST**.

1. For **Action type**, choose **Use action name**.

1. For **Action name**, enter **PutRecords**.

1. For **Execution role**, enter the ARN for your execution role.

1. Keep the default of **Passthrough** for **Content Handling**.

1. Choose **Create method**.

1. In the **Integration request** section, add the following **URL request headers parameters**:

   ```
   Content-Type: 'x-amz-json-1.1'
   ```

   The task follows the same procedure to set up the request parameter mapping for the `GET /streams` method.

1.  Add the following mapping template to map data from the `PUT /streams/{stream-name}/records` method request to the corresponding integration request of `POST /?Action=PutRecords` : 

   ```
   {
       "StreamName": "$input.params('stream-name')",
       "Records": [
          #foreach($elem in $input.path('$.records'))
             {
               "Data": "$util.base64Encode($elem.data)",
               "PartitionKey": "$elem.partition-key"
             }#if($foreach.hasNext),#end
           #end
       ]
   }
   ```

   This mapping template assumes that the method request payload can be modelled by the following JSON schema:

   ```
   {
     "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "PutRecords proxy payload data",
     "type": "object",
     "properties": {
       "records": {
         "type": "array",
         "items": {
           "type": "object",
           "properties": {
             "data": { "type": "string" },
             "partition-key": { "type": "string" }
           }
         }
       }
     }
   }
   ```

    You can create a model to include this schema and use the model to facilitate generating the mapping template. However, you can generate a mapping template without using any model. 

   In this tutorial, we used two slightly different payload formats to illustrate that an API developer can choose to expose the backend data format to the client or hide it from the client. One format is for the `PUT /streams/{stream-name}/records` method (above). Another format is used for the `PUT /streams/{stream-name}/record` method (in the previous procedure). In production environment, you should keep both formats consistent. 

1. 

    To test the `PUT /streams/{stream-name}/records` method, set the `stream-name` path variable to an existing stream, supply the following payload, and submit the method request. 

   ```
   {
       "records": [
           {
               "data": "some data",
               "partition-key": "some key"
           },
           {
               "data": "some other data",
               "partition-key": "some key"
           }
       ]
   }
   ```

   The successful result is a 200 OK response with a payload similar to the following output: 

   ```
   {
     "FailedRecordCount": 0,
     "Records": [
       {
         "SequenceNumber": "49559409944537880850133345460167468741933742152373764162",
         "ShardId": "shardId-000000000004"
       },
       {
         "SequenceNumber": "49559409944537880850133345460168677667753356781548470338",
         "ShardId": "shardId-000000000004"
       }
     ]
   }
   ```

**To set up and test the `GET /streams/{stream-name}/sharditerator` method invoke `GetShardIterator` in Kinesis**

The `GET /streams/{stream-name}/sharditerator` method is a helper method to acquire a required shard iterator before calling the `GET /streams/{stream-name}/records` method.

1. Choose the **/sharditerator** resource, and then choose **Create method**.

1. For **Method type**, select **GET**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Kinesis stream. 

1. For **AWS service**, select **Kinesis**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, choose **POST**.

1. For **Action type**, choose **Use action name**.

1. For **Action name**, enter **GetShardIterator**.

1. For **Execution role**, enter the ARN for your execution role.

1. Keep the default of **Passthrough** for **Content Handling**.

1. Choose **URL query string parameters**.

   The `GetShardIterator` action requires an input of a ShardId value. To pass a client-supplied `ShardId` value, we add a `shard-id` query parameter to the method request, as shown in the following step. 

1. Choose **Add query string**.

1. For **Name**, enter **shard-id**.

1. Keep **Required** and **Caching** turned off.

1. Choose **Create method**.

1. In the **Integration request** section, add the following mapping template to generate the required input (`ShardId` and `StreamName`) to the `GetShardIterator` action from the `shard-id` and `stream-name` parameters of the method request. In addition, the mapping template also sets `ShardIteratorType` to `TRIM_HORIZON` as a default.

   ```
   {
       "ShardId": "$input.params('shard-id')",
       "ShardIteratorType": "TRIM_HORIZON",
       "StreamName": "$input.params('stream-name')"
   }
   ```

1.  Using the **Test** option in the API Gateway console, enter an existing stream name as the `stream-name` **Path** variable value, set the `shard-id` **Query string** to an existing `ShardId` value (e.g., `shard-000000000004`), and choose **Test**. 

    The successful response payload is similar to the following output: 

   ```
   {
     "ShardIterator": "AAAAAAAAAAFYVN3VlFy..."
   }
   ```

   Make note of the `ShardIterator` value. You need it to get records from a stream.

**To configure and test the `GET /streams/{stream-name}/records` method to invoke the `GetRecords` action in Kinesis**

1. Choose the **/records** resource, and then choose **Create method**.

1. For **Method type**, select **GET**.

1. For **Integration type**, select **AWS service**.

1. For **AWS Region**, select the AWS Region where you created your Kinesis stream. 

1. For **AWS service**, select **Kinesis**.

1. Keep **AWS subdomain** blank.

1. For **HTTP method**, choose **POST**.

1. For **Action type**, choose **Use action name**.

1. For **Action name**, enter **GetRecords**.

1. For **Execution role**, enter the ARN for your execution role.

1. Keep the default of **Passthrough** for **Content Handling**.

1. Choose **HTTP request headers**.

    The `GetRecords` action requires an input of a `ShardIterator` value. To pass a client-supplied `ShardIterator` value, we add a `Shard-Iterator` header parameter to the method request.

1. Choose **Add header**.

1. For **Name**, enter **Shard-Iterator**.

1. Keep **Required** and **Caching** turned off.

1. Choose **Create method**.

1.  In the **Integration request** section, add the following body mapping template to map the `Shard-Iterator` header parameter value to the `ShardIterator` property value of the JSON payload for the `GetRecords` action in Kinesis. 

   ```
   {
       "ShardIterator": "$input.params('Shard-Iterator')"
   }
   ```

1.  Using the **Test** option in the API Gateway console, enter an existing stream name as the `stream-name` **Path** variable value, set the `Shard-Iterator` **Header** to the `ShardIterator` value obtained from the test run of the `GET /streams/{stream-name}/sharditerator` method (above), and choose **Test**. 

    The successful response payload is similar to the following output: 

   ```
   {
     "MillisBehindLatest": 0,
     "NextShardIterator": "AAAAAAAAAAF...",
     "Records": [ ... ]
   }
   ```

# OpenAPI definitions of a sample API as a Kinesis proxy
<a name="api-as-kinesis-proxy-export-swagger-with-extensions"></a>

Following are OpenAPI definitions for the sample API as a Kinesis proxy used in this tutorial. 

------
#### [ OpenAPI 3.0 ]

```
{
  "openapi": "3.0.0",
  "info": {
    "title": "KinesisProxy",
    "version": "2016-03-31T18:25:32Z"
  },
  "paths": {
    "/streams/{stream-name}/sharditerator": {
      "get": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "shard-id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/GetShardIterator",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardId\": \"$input.params('shard-id')\",\n    \"ShardIteratorType\": \"TRIM_HORIZON\",\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}/records": {
      "get": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Shard-Iterator",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/GetRecords",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardIterator\": \"$input.params('Shard-Iterator')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "put": {
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PutRecordsMethodRequestPayload"
              }
            },
            "application/x-amz-json-1.1": {
              "schema": {
                "$ref": "#/components/schemas/PutRecordsMethodRequestPayload"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/PutRecords",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\",\n    \"Records\": [\n          {\n            \"Data\": \"$util.base64Encode($elem.data)\",\n            \"PartitionKey\": \"$elem.partition-key\"\n          }#if($foreach.hasNext),#end\n    ]\n}",
            "application/x-amz-json-1.1": "{\n  \"StreamName\": \"$input.params('stream-name')\",\n  \"records\" : [\n    {\n        \"Data\" : \"$elem.data\",\n        \"PartitionKey\" : \"$elem.partition-key\"\n    }#if($foreach.hasNext),#end\n  ]\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}": {
      "get": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/DescribeStream",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "post": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/CreateStream",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardCount\": 5,\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "delete": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "headers": {
              "Content-Type": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "headers": {
              "Content-Type": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {}
          },
          "500": {
            "description": "500 response",
            "headers": {
              "Content-Type": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {}
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/DeleteStream",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            },
            "5\\d{2}": {
              "statusCode": "500",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}/record": {
      "put": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/PutRecord",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\",\n    \"Data\": \"$util.base64Encode($input.json('$.Data'))\",\n    \"PartitionKey\": \"$input.path('$.PartitionKey')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams": {
      "get": {
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/ListStreams",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Empty": {
        "type": "object"
      },
      "PutRecordsMethodRequestPayload": {
        "type": "object",
        "properties": {
          "records": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "data": {
                  "type": "string"
                },
                "partition-key": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}
```

------
#### [ OpenAPI 2.0 ]

```
{
  "swagger": "2.0",
  "info": {
    "version": "2016-03-31T18:25:32Z",
    "title": "KinesisProxy"
  },
  "basePath": "/test",
  "schemes": [
    "https"
  ],
  "paths": {
    "/streams": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/ListStreams",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/DescribeStream",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "post": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/CreateStream",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardCount\": 5,\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "delete": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response",
            "headers": {
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "500": {
            "description": "500 response",
            "headers": {
              "Content-Type": {
                "type": "string"
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/DeleteStream",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            },
            "5\\d{2}": {
              "statusCode": "500",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}/record": {
      "put": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/PutRecord",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\",\n    \"Data\": \"$util.base64Encode($input.json('$.Data'))\",\n    \"PartitionKey\": \"$input.path('$.PartitionKey')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}/records": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "Shard-Iterator",
            "in": "header",
            "required": false,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/GetRecords",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardIterator\": \"$input.params('Shard-Iterator')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "put": {
        "consumes": [
          "application/json",
          "application/x-amz-json-1.1"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "required": false,
            "type": "string"
          },
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "in": "body",
            "name": "PutRecordsMethodRequestPayload",
            "required": true,
            "schema": {
              "$ref": "#/definitions/PutRecordsMethodRequestPayload"
            }
          },
          {
            "in": "body",
            "name": "PutRecordsMethodRequestPayload",
            "required": true,
            "schema": {
              "$ref": "#/definitions/PutRecordsMethodRequestPayload"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/PutRecords",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\",\n    \"Records\": [\n          {\n            \"Data\": \"$util.base64Encode($elem.data)\",\n            \"PartitionKey\": \"$elem.partition-key\"\n          }#if($foreach.hasNext),#end\n    ]\n}",
            "application/x-amz-json-1.1": "{\n  \"StreamName\": \"$input.params('stream-name')\",\n  \"records\" : [\n    {\n        \"Data\" : \"$elem.data\",\n        \"PartitionKey\" : \"$elem.partition-key\"\n    }#if($foreach.hasNext),#end\n  ]\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}/sharditerator": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "shard-id",
            "in": "query",
            "required": false,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/GetShardIterator",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardId\": \"$input.params('shard-id')\",\n    \"ShardIteratorType\": \"TRIM_HORIZON\",\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    }
  },
  "definitions": {
    "Empty": {
      "type": "object"
    },
    "PutRecordsMethodRequestPayload": {
      "type": "object",
      "properties": {
        "records": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "data": {
                "type": "string"
              },
              "partition-key": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}
```

------

# Tutorial: Create a REST API using AWS SDKs or the AWS CLI
<a name="api-gateway-create-api-cli-sdk"></a>

Use the following tutorial to create a PetStore API supporting the `GET /pets` and `GET /pets/{petId}` methods. The methods are integrated with an HTTP endpoint. You can follow this tutorial using the AWS SDK for JavaScript, the SDK for Python (Boto3), or the AWS CLI. You use the following functions or commands to set up your API:

------
#### [ JavaScript v3 ]
+ [ CreateRestApiCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/CreateRestApiCommand/)
+ [ CreateResourceCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/CreateResourceCommand/)
+ [ PutMethodCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/PutMethodCommand/)
+ [ PutMethodResponseCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/PutMethodResponseCommand/)
+ [ PutIntegrationCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/PutIntegrationCommand/)
+ [ PutIntegrationResponseCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/PutIntegrationResponseCommand/)
+ [ CreateDeploymentCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/CreateDeploymentCommand/)

------
#### [ Python ]
+ [ create\$1rest\$1api](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/create_rest_api.html)
+ [ create\$1resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/create_resource.html)
+ [ put\$1method](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/put_method.html)
+ [ put\$1method\$1response](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/put_method_response.html)
+ [ put\$1integration](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/put_integration.html)
+ [ put\$1integration\$1response](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/put_integration_response.html)
+ [ create\$1deployment](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/create_deployment.html)

------
#### [ AWS CLI ]
+ [create-rest-api](https://docs.aws.amazon.com/cli/latest/reference/apigateway/create-rest-api.html)
+  [create-resource](https://docs.aws.amazon.com/cli/latest/reference/apigateway/create-resource.html) 
+  [put-method](https://docs.aws.amazon.com/cli/latest/reference/apigateway/put-method.html) 
+  [put-method-response](https://docs.aws.amazon.com/cli/latest/reference/apigateway/put-method-response.html) 
+  [put-integration](https://docs.aws.amazon.com/cli/latest/reference/apigateway/put-integration.html) 
+  [put-integration-response](https://docs.aws.amazon.com/cli/latest/reference/apigateway/put-integration-response.html) 
+  [create-deployment](https://docs.aws.amazon.com/cli/latest/reference/apigateway/create-deployment.html) 

------

For more information about the AWS SDK for JavaScript v3, see [What's the AWS SDK for JavaScript?](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/welcome.html). For more information about the SDK for Python (Boto3), see [AWS SDK for Python (Boto3)](https://docs.aws.amazon.com/pythonsdk). For more information about the AWS CLI, see [What is the AWS CLI?](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html).

## Set up an edge-optimized PetStore API
<a name="api-gateway-create-api-cli-sdk-tutorial"></a>

In this tutorial, example commands use placeholder values for value IDs such as API ID and resource ID. As you complete the tutorial, replace these values with your own.

**To set up an edge-optimized PetStore API using AWS SDKs**

1. Use the following example to create a `RestApi` entity:

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient, CreateRestApiCommand} from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new CreateRestApiCommand({
       name: "Simple PetStore (JavaScript v3 SDK)",
       description: "Demo API created using the AWS SDK for JavaScript v3",
       version: "0.00.001",
       binaryMediaTypes: [
       '*']
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.error(Couldn't create API:\n", err)
   }
   })();
   ```

   A successful call returns your API ID and the root resource ID of your API in an output like the following:

   ```
   {
     id: 'abc1234',
     name: 'PetStore (JavaScript v3 SDK)',
     description: 'Demo API created using the AWS SDK for node.js',
     createdDate: 2017-09-05T19:32:35.000Z,
     version: '0.00.001',
     rootResourceId: 'efg567'
     binaryMediaTypes: [ '*' ] 
   }
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.create_rest_api(
           name='Simple PetStore (Python SDK)',
           description='Demo API created using the AWS SDK for Python',
           version='0.00.001',
           binaryMediaTypes=[
               '*'
           ]
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Couldn't create REST API %s.", error)
       raise
   attribute=["id","name","description","createdDate","version","binaryMediaTypes","apiKeySource","endpointConfiguration","disableExecuteApiEndpoint","rootResourceId"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   A successful call returns your API ID and the root resource ID of your API in an output like the following:

   ```
   {'id': 'abc1234', 'name': 'Simple PetStore (Python SDK)', 'description': 'Demo API created using the AWS SDK for Python', 'createdDate': datetime.datetime(2024, 4, 3, 14, 31, 39, tzinfo=tzlocal()), 'version': '0.00.001', 'binaryMediaTypes': ['*'], 'apiKeySource': 'HEADER', 'endpointConfiguration': {'types': ['EDGE']}, 'disableExecuteApiEndpoint': False, 'rootResourceId': 'efg567'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway create-rest-api --name 'Simple PetStore (AWS CLI)' --region us-west-2
   ```

   The following is the output of this command:

   ```
   {
       "id": "abcd1234", 
       "name": "Simple PetStore (AWS CLI)", 
       "createdDate": "2022-12-15T08:07:04-08:00",
       "apiKeySource": "HEADER",
       "endpointConfiguration": {
           "types": [
               "EDGE"
           ]
       },
       "disableExecuteApiEndpoint": false,
       "rootResourceId": "efg567"
   }
   ```

------

   The API you created has an API ID of `abcd1234` and a root resource ID of `efg567`. You use these values in the set up of your API.

1. Next, you append a child resource under the root, you specify the `RootResourceId` as the `parentId` property value. Use the following example to create a `/pets` resource for your API:

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  CreateResourceCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new CreateResourceCommand({
       restApiId: 'abcd1234',
       parentId: 'efg567',
       pathPart: 'pets'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The '/pets' resource setup failed:\n", err)
   }
   })();
   ```

   A successful call returns information about your resource in an output like the following:

   ```
   {
       "path": "/pets", 
       "pathPart": "pets", 
       "id": "aaa111", 
       "parentId": "efg567'"
   }
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.create_resource(
           restApiId='abcd1234',
           parentId='efg567',
           pathPart='pets'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("The '/pets' resource setup failed: %s.", error)
       raise
   attribute=["id","parentId", "pathPart", "path",]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   A successful call returns information about your resource in an output like the following:

   ```
   {'id': 'aaa111', 'parentId': 'efg567', 'pathPart': 'pets', 'path': '/pets'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway create-resource --rest-api-id abcd1234 \
     --region us-west-2 \
     --parent-id efg567 \
     --path-part pets
   ```

   The following is the output of this command:

   ```
   {
       "id": "aaa111", 
       "parentId": "efg567",
       "pathPart": "pets",
       "path": "/pets"
   }
   ```

------

   The `/pets` resource you created has a resource ID of `aaa111`. You use this value in the set up of your API.

1. Next, you append a child resource under the `/pets` resource. This resource, `/{petId}` has a path parameter for the `{petId}`.To make a path part a path parameter, enclose it in a pair of curly brackets, `{ }`. Use the following example to create a `/pets/{petId}` resource for your API:

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  CreateResourceCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new CreateResourceCommand({
       restApiId: 'abcd1234',
       parentId: 'aaa111',
       pathPart: '{petId}'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The '/pets/{petId}' resource setup failed:\n", err)
   }
   })();
   ```

   A successful call returns information about your resource in an output like the following:

   ```
   {
       "path": "/pets/{petId}", 
       "pathPart": "{petId}", 
       "id": "bbb222", 
       "parentId": "aaa111'"
   }
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.create_resource(
           restApiId='abcd1234',
           parentId='aaa111',
           pathPart='{petId}'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("The '/pets/{petId}' resource setup failed: %s.", error)
       raise
   attribute=["id","parentId", "pathPart", "path",]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   A successful call returns information about your resource in an output like the following:

   ```
   {'id': 'bbb222', 'parentId': 'aaa111', 'pathPart': '{petId}', 'path': '/pets/{petId}'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway create-resource --rest-api-id abcd1234 \
     --region us-west-2 \
     --parent-id aaa111 \
     --path-part '{petId}'
   ```

   The following is the output of this command:

   ```
   {
       "id": "bbb222",
       "parentId": "aaa111",
       "path": "/pets/{petId}", 
       "pathPart": "{petId}"
   }
   ```

------

   The `/pets/{petId}` resource you created has a resource ID of `bbb222`. You use this value in the set up of your API.

1. In the following two steps, you add HTTP methods to your resources. In this tutorial, you set the methods to have open access by setting the `authorization-type` to set to `NONE`. To permit only authenticated users to call the method, you can use IAM roles and policies, a Lambda authorizer (formerly known as a custom authorizer), or an Amazon Cognito user pool. For more information, see [Control and manage access to REST APIs in API Gateway](apigateway-control-access-to-api.md).

   Use the following example to add the `GET` HTTP method on the `/pets` resource:

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  PutMethodCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutMethodCommand({
       restApiId: 'abcd1234',
       resourceId: 'aaa111',
       httpMethod: 'GET',
       authorizationType: 'NONE'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The 'GET /pets' method setup failed:\n", err)
   }
   })();
   ```

   A successful call returns the following output:

   ```
   {
       "apiKeyRequired": false, 
       "httpMethod": "GET", 
       "authorizationType": "NONE"
   }
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_method(
           restApiId='abcd1234',
           resourceId='aaa111',
           httpMethod='GET',
           authorizationType='NONE'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("The 'GET /pets' method setup failed: %s", error)
       raise
   attribute=["httpMethod","authorizationType","apiKeyRequired"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   A successful call returns the following output:

   ```
   {'httpMethod': 'GET', 'authorizationType': 'NONE', 'apiKeyRequired': False}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-method --rest-api-id abcd1234 \
     --resource-id aaa111 \
     --http-method GET \
     --authorization-type "NONE" \
     --region us-west-2
   ```

   The following is the output of this command:

   ```
   {
       "httpMethod": "GET", 
       "authorizationType": "NONE",
       "apiKeyRequired": false
   }
   ```

------

1. Use the following example to add the `GET` HTTP method on the `/pets/{petId}` resource and to set the `requestParameters` property to pass the client-supplied `petId` value to the backend:

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  PutMethodCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutMethodCommand({
       restApiId: 'abcd1234',
       resourceId: 'bbb222',
       httpMethod: 'GET',
       authorizationType: 'NONE'
       requestParameters: {
           "method.request.path.petId" : true
       }
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The 'GET /pets/{petId}' method setup failed:\n", err)
   }
   })();
   ```

   A successful call returns the following output:

   ```
   {
       "apiKeyRequired": false, 
       "httpMethod": "GET", 
       "authorizationType": "NONE",
       "requestParameters": {
          "method.request.path.petId": true
       }
   }
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_method(
           restApiId='abcd1234',
           resourceId='bbb222',
           httpMethod='GET',
           authorizationType='NONE',
           requestParameters={
               "method.request.path.petId": True
           }
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("The 'GET /pets/{petId}' method setup failed: %s", error)
       raise
   attribute=["httpMethod","authorizationType","apiKeyRequired", "requestParameters" ]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   A successful call returns the following output:

   ```
   {'httpMethod': 'GET', 'authorizationType': 'NONE', 'apiKeyRequired': False, 'requestParameters': {'method.request.path.petId': True}}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-method --rest-api-id abcd1234 \
     --resource-id bbb222 --http-method GET \
     --authorization-type "NONE" \
     --region us-west-2 \
     --request-parameters method.request.path.petId=true
   ```

   The following is the output of this command:

   ```
   {
       "httpMethod": "GET", 
       "authorizationType": "NONE", 
       "apiKeyRequired": false, 
       "requestParameters": {
           "method.request.path.petId": true
       }
   }
   ```

------

1. Use the following example to add the 200 OK method response for the `GET /pets` method:

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  PutMethodResponseCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutMethodResponseCommand({
       restApiId: 'abcd1234',
       resourceId: 'aaa111',
       httpMethod: 'GET',
       statusCode: '200'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("Set up the 200 OK response for the 'GET /pets' method failed:\n", err)
   }
   })();
   ```

   A successful call returns the following output:

   ```
   {
       "statusCode": "200"
   }
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_method_response(
           restApiId='abcd1234',
           resourceId='aaa111',
           httpMethod='GET',
           statusCode='200'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the 200 OK response for the 'GET /pets' method failed %s.", error)
       raise
   attribute=["statusCode"]
   filtered_result ={key:result[key] for key in attribute}
   logger.info(filtered_result)
   ```

   A successful call returns the following output:

   ```
   {'statusCode': '200'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-method-response --rest-api-id abcd1234 \ 
     --resource-id aaa111 --http-method GET \
     --status-code 200  --region us-west-2
   ```

   The following is the output of this command:

   ```
   {
       "statusCode": "200"
   }
   ```

------

1. Use the following example to add the 200 OK method response for the `GET /pets/{petId}` method:

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  PutMethodResponseCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutMethodResponseCommand({
       restApiId: 'abcd1234',
       resourceId: 'bbb222',
       httpMethod: 'GET',
       statusCode: '200'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("Set up the 200 OK response for the 'GET /pets/{petId}' method failed:\n", err)
   }
   })();
   ```

   A successful call returns the following output:

   ```
   {
       "statusCode": "200"
   }
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_method_response(
           restApiId='abcd1234',
           resourceId='bbb222',
           httpMethod='GET',
           statusCode='200'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the 200 OK response for the 'GET /pets/{petId}' method failed %s.", error)
       raise
   attribute=["statusCode"]
   filtered_result ={key:result[key] for key in attribute}
   logger.info(filtered_result)
   ```

   A successful call returns the following output:

   ```
   {'statusCode': '200'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-method-response --rest-api-id abcd1234 \ 
     --resource-id bbb222 --http-method GET \
     --status-code 200  --region us-west-2
   ```

   The following is the output of this command:

   ```
   {
       "statusCode": "200"
   }
   ```

------

1. Use the following example to configure an integration for the `GET /pets` method with an HTTP endpoint. The HTTP endpoint is `http://petstore-demo-endpoint.execute-api.com/petstore/pets`.

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  PutIntegrationCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutIntegrationCommand({
       restApiId: 'abcd1234',
       resourceId: 'aaa111',
       httpMethod: 'GET',
       type: 'HTTP',
       integrationHttpMethod: 'GET',
       uri: 'http://petstore-demo-endpoint.execute-api.com/petstore/pets'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("Set up the integration of the 'GET /pets' method of the API failed:\n", err)
   }
   })();
   ```

   A successful call returns the following output:

   ```
   {
       "httpMethod": "GET", 
       "passthroughBehavior": "WHEN_NO_MATCH", 
       "cacheKeyParameters": [], 
       "type": "HTTP", 
       "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets", 
       "cacheNamespace": "ccc333"
   }
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_integration(
           restApiId='abcd1234',
           resourceId='aaa111',
           httpMethod='GET',
           type='HTTP',
           integrationHttpMethod='GET',
           uri='http://petstore-demo-endpoint.execute-api.com/petstore/pets'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the integration of the 'GET /' method of the API failed %s.", error)
       raise
   attribute=["httpMethod","passthroughBehavior","cacheKeyParameters", "type", "uri", "cacheNamespace"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   A successful call returns the following output:

   ```
   {'httpMethod': 'GET', 'passthroughBehavior': 'WHEN_NO_MATCH', 'cacheKeyParameters': [], 'type': 'HTTP', 'uri': 'http://petstore-demo-endpoint.execute-api.com/petstore/pets', 'cacheNamespace': 'ccc333'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-integration --rest-api-id abcd1234 \
     --resource-id aaa111 --http-method GET --type HTTP \
     --integration-http-method GET \
     --uri 'http://petstore-demo-endpoint.execute-api.com/petstore/pets' \
     --region us-west-2
   ```

   The following is the output of this command:

   ```
   {
       "type": "HTTP",
       "httpMethod": "GET",
       "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets",
       "connectionType": "INTERNET",
       "passthroughBehavior": "WHEN_NO_MATCH",
       "timeoutInMillis": 29000,
       "cacheNamespace": "6sxz2j",
       "cacheKeyParameters": []
   }
   ```

------

1. Use the following example to configure an integration for the `GET /pets/{petId}` method with an HTTP endpoint. The HTTP endpoint is `http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}`. In this step, you map the path parameter `petId` to the integration endpoint path parameter of `id`.

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  PutIntegrationCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutIntegrationCommand({
       restApiId: 'abcd1234',
       resourceId: 'bbb222',
       httpMethod: 'GET',
       type: 'HTTP',
       integrationHttpMethod: 'GET',
       uri: 'http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}'
       requestParameters: {
           "integration.request.path.id": "method.request.path.petId"
        }
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("Set up the integration of the 'GET /pets/{petId}' method of the API failed:\n", err)
   }
   })();
   ```

   A successful call returns the following output:

   ```
   {
       "httpMethod": "GET", 
       "passthroughBehavior": "WHEN_NO_MATCH", 
       "cacheKeyParameters": [], 
       "type": "HTTP", 
       "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}", 
       "cacheNamespace": "ddd444",
       "requestParameters": {
          "integration.request.path.id": "method.request.path.petId"
       }
   }
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_integration(
           restApiId='ieps9b05sf',
           resourceId='t8zeb4',
           httpMethod='GET',
           type='HTTP',
           integrationHttpMethod='GET',
           uri='http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}',
           requestParameters={
               "integration.request.path.id": "method.request.path.petId"
           }
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the integration of the 'GET /pets/{petId}' method of the API failed %s.", error)
       raise
   attribute=["httpMethod","passthroughBehavior","cacheKeyParameters", "type", "uri", "cacheNamespace", "requestParameters"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   A successful call returns the following output:

   ```
   {'httpMethod': 'GET', 'passthroughBehavior': 'WHEN_NO_MATCH', 'cacheKeyParameters': [], 'type': 'HTTP', 'uri': 'http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}', 'cacheNamespace': 'ddd444', 'requestParameters': {'integration.request.path.id': 'method.request.path.petId'}}}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-integration --rest-api-id abcd1234 \
     --resource-id bbb222 --http-method GET --type HTTP \
     --integration-http-method GET \
     --uri 'http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}' \ 
     --request-parameters '{"integration.request.path.id":"method.request.path.petId"}' \
     --region us-west-2
   ```

   The following is the output of this command:

   ```
   {
       "type": "HTTP",
       "httpMethod": "GET",
       "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}",
       "connectionType": "INTERNET",
       "requestParameters": {
           "integration.request.path.id": "method.request.path.petId"
       },
       "passthroughBehavior": "WHEN_NO_MATCH",
       "timeoutInMillis": 29000,
       "cacheNamespace": "rjkmth",
       "cacheKeyParameters": []
   }
   ```

------

1. Use the following example to add the integration response for the `GET /pets` integration:

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  PutIntegrationResponseCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutIntegrationResponseCommand({
       restApiId: 'abcd1234',
       resourceId: 'aaa111',
       httpMethod: 'GET',
       statusCode: '200',
       selectionPattern: ''
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The 'GET /pets' method integration response setup failed:\n", err)
   }
   })();
   ```

   A successful call returns the following output:

   ```
   {
       "selectionPattern": "", 
       "statusCode": "200"
   }
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_integration_response(
           restApiId='abcd1234',
           resourceId='aaa111',
           httpMethod='GET',
           statusCode='200',
           selectionPattern='',
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the integration response of the 'GET /pets' method of the API failed: %s", error)
       raise
   attribute=["selectionPattern","statusCode"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   A successful call returns the following output:

   ```
   {'selectionPattern': "", 'statusCode': '200'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-integration-response --rest-api-id abcd1234 \
     --resource-id aaa111 --http-method GET \
     --status-code 200 --selection-pattern ""  \
     --region us-west-2
   ```

   The following is the output of this command:

   ```
   {
       "statusCode": "200",
       "selectionPattern": "" 
   }
   ```

------

1. Use the following example to add the integration response for the `GET /pets/{petId}` integration:

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  PutIntegrationResponseCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutIntegrationResponseCommand({
       restApiId: 'abcd1234',
       resourceId: 'bbb222',
       httpMethod: 'GET',
       statusCode: '200',
       selectionPattern: ''
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The 'GET /pets/{petId}' method integration response setup failed:\n", err)
   }
   })();
   ```

   A successful call returns the following output:

   ```
   {
       "selectionPattern": "", 
       "statusCode": "200"
   }
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_integration_response(
           restApiId='abcd1234',
           resourceId='bbb222',
           httpMethod='GET',
           statusCode='200',
           selectionPattern='',
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the integration response of the 'GET /pets/{petId}' method of the API failed: %s", error)
       raise
   attribute=["selectionPattern","statusCode"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   A successful call returns the following output:

   ```
   {'selectionPattern': "", 'statusCode': '200'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-integration-response --rest-api-id abcd1234 \
     --resource-id bbb222 --http-method GET 
     --status-code 200 --selection-pattern ""  
     --region us-west-2
   ```

   The following is the output of this command:

   ```
   {
       "statusCode": "200",
       "selectionPattern": "" 
   }
   ```

------

   After you create the integration response, your API can query available pets on the PetStore website and to view an individual pet of a specified identifier. Before your API is callable by your customers, you must deploy it. We recommend that before you deploy your API, you test it.

1. Use the following example to test the `GET /pets` method: 

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  TestInvokeMethodCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new TestInvokeMethodCommand({
       restApiId: 'abcd1234',
       resourceId: 'aaa111',
       httpMethod: 'GET',
       pathWithQueryString: '/',
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The test on 'GET /pets' method failed:\n", err)
   }
   })();
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.test_invoke_method(
           restApiId='abcd1234',
           resourceId='aaa111',
           httpMethod='GET',
           pathWithQueryString='/',
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Test invoke method on 'GET /pets' failed: %s", error)
       raise
   print(result)
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway test-invoke-method --rest-api-id abcd1234 /
     --resource-id aaa111 /
     --http-method GET /
     --path-with-query-string '/'
   ```

------

1. Use the following example to test the `GET /pets/{petId}` method with a `petId` of 3:

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  TestInvokeMethodCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new TestInvokeMethodCommand({
       restApiId: 'abcd1234',
       resourceId: 'bbb222',
       httpMethod: 'GET',
       pathWithQueryString: '/pets/3',
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The test on 'GET /pets/{petId}' method failed:\n", err)
   }
   })();
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.test_invoke_method(
           restApiId='abcd1234',
           resourceId='bbb222',
           httpMethod='GET',
           pathWithQueryString='/pets/3',
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Test invoke method on 'GET /pets/{petId}' failed: %s", error)
       raise
   print(result)
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway test-invoke-method --rest-api-id abcd1234 /
     --resource-id bbb222 /
     --http-method GET /
     --path-with-query-string '/pets/3'
   ```

------

   After you successfully test your API, you can deploy it to a stage.

1. Use the following example to deploy your API to a stage named `test`. When you deploy your API to a stage, API callers can invoke your API.

------
#### [ JavaScript v3 ]

   ```
   import {APIGatewayClient,  CreateDeploymentCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new CreateDeploymentCommand({
       restApiId: 'abcd1234',
       stageName: 'test',
       stageDescription: 'test deployment'
   });
   try {
       const results = await apig.send(command)
       console.log("Deploying API succeeded\n", results)
   } catch (err) {
       console.log("Deploying API failed:\n", err)
   }
   })();
   ```

------
#### [ Python ]

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.create_deployment(
           restApiId='ieps9b05sf',
           stageName='test',
           stageDescription='my test stage',
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Error deploying stage  %s.", error)
       raise
   print('Deploying API succeeded')
   print(result)
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway create-deployment --rest-api-id abcd1234 \ 
     --region us-west-2 \
     --stage-name test \
     --stage-description 'Test stage' \
     --description 'First deployment'
   ```

   The following is the output of this command:

   ```
   {
       "id": "ab1c1d",
       "description": "First deployment",
       "createdDate": "2022-12-15T08:44:13-08:00"
   }
   ```

------

   Your API is now callable by customers. You can test this API by entering the `https://abcd1234.execute-api.us-west-2.amazonaws.com/test/pets` URL in a browser, and substituting `abcd1234` with the identifier of your API.

For more examples of how to create or update an API using AWS SDKs or the AWS CLI, see [Actions for API Gateway using AWS SDKs](https://docs.aws.amazon.com/code-library/latest/ug/api-gateway_code_examples_actions.html).

## Automate the setup of your API
<a name="api-gateway-create-api-cli-sdk-iac"></a>

Instead of creating your API step-by-step, you can automate the creation and cleanup of AWS resources by using OpenAPI, CloudFormation, or Terraform to create your API.

### OpenAPI 3.0 definition
<a name="api-gateway-create-api-cli-sdk-template-OpenAPI"></a>

You can import an OpenAPI defintion into API Gateway. For more information, see [Develop REST APIs using OpenAPI in API Gateway](api-gateway-import-api.md).

```
{
  "openapi" : "3.0.1",
  "info" : {
    "title" : "Simple PetStore (OpenAPI)",
    "description" : "Demo API created using OpenAPI",
    "version" : "2024-05-24T20:39:34Z"
  },
  "servers" : [ {
    "url" : "{basePath}",
    "variables" : {
      "basePath" : {
        "default" : "Prod"
      }
    }
  } ],
  "paths" : {
    "/pets" : {
      "get" : {
        "responses" : {
          "200" : {
            "description" : "200 response",
            "content" : { }
          }
        },
        "x-amazon-apigateway-integration" : {
          "type" : "http",
          "httpMethod" : "GET",
          "uri" : "http://petstore-demo-endpoint.execute-api.com/petstore/pets",
          "responses" : {
            "default" : {
              "statusCode" : "200"
            }
          },
          "passthroughBehavior" : "when_no_match",
          "timeoutInMillis" : 29000
        }
      }
    },
    "/pets/{petId}" : {
      "get" : {
        "parameters" : [ {
          "name" : "petId",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "200 response",
            "content" : { }
          }
        },
        "x-amazon-apigateway-integration" : {
          "type" : "http",
          "httpMethod" : "GET",
          "uri" : "http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}",
          "responses" : {
            "default" : {
              "statusCode" : "200"
            }
          },
          "requestParameters" : {
            "integration.request.path.id" : "method.request.path.petId"
          },
          "passthroughBehavior" : "when_no_match",
          "timeoutInMillis" : 29000
        }
      }
    }
  },
  "components" : { }
}
```

### AWS CloudFormation template
<a name="api-gateway-create-api-cli-sdk-template-CloudFormation"></a>

To deploy your CloudFormation template, see [Creating a stack on the AWS CloudFormation console](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-create-stack.html).

```
AWSTemplateFormatVersion: 2010-09-09
Resources:
  Api:
    Type: 'AWS::ApiGateway::RestApi'
    Properties:
      Name: Simple PetStore (AWS CloudFormation)
  PetsResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref Api
      ParentId: !GetAtt Api.RootResourceId
      PathPart: 'pets'
  PetIdResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref Api
      ParentId: !Ref PetsResource
      PathPart: '{petId}'
  PetsMethodGet:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      RestApiId: !Ref Api
      ResourceId: !Ref PetsResource
      HttpMethod: GET
      AuthorizationType: NONE
      Integration:
        Type: HTTP
        IntegrationHttpMethod: GET
        Uri: http://petstore-demo-endpoint.execute-api.com/petstore/pets/
        IntegrationResponses:
          - StatusCode: '200'
      MethodResponses:
        - StatusCode: '200'
  PetIdMethodGet:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      RestApiId: !Ref Api
      ResourceId: !Ref PetIdResource
      HttpMethod: GET
      AuthorizationType: NONE
      RequestParameters: 
        method.request.path.petId: true
      Integration:
        Type: HTTP
        IntegrationHttpMethod: GET
        Uri: http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}
        RequestParameters:
          integration.request.path.id: method.request.path.petId
        IntegrationResponses:
          - StatusCode: '200'
      MethodResponses:
        - StatusCode: '200'
  ApiDeployment:
    Type: 'AWS::ApiGateway::Deployment'
    DependsOn:
      - PetsMethodGet
    Properties:
      RestApiId: !Ref Api
      StageName: Prod
Outputs:
  ApiRootUrl:
    Description: Root Url of the API
    Value: !Sub 'https://${Api}.execute-api.${AWS::Region}.amazonaws.com/Prod'
```

### Terraform configuration
<a name="api-gateway-create-api-cli-sdk-template-terraform"></a>

For more information about Terraform, see [Terraform](https://developer.hashicorp.com/terraform/intro).

```
provider "aws" {
  region = "us-east-1" # Update with your desired region
}
resource "aws_api_gateway_rest_api" "Api" {
  name        = "Simple PetStore (Terraform)"
  description = "Demo API created using Terraform"
}
resource "aws_api_gateway_resource" "petsResource"{
    rest_api_id = aws_api_gateway_rest_api.Api.id
    parent_id = aws_api_gateway_rest_api.Api.root_resource_id
    path_part = "pets"
}
resource "aws_api_gateway_resource" "petIdResource"{
    rest_api_id = aws_api_gateway_rest_api.Api.id
    parent_id = aws_api_gateway_resource.petsResource.id
    path_part = "{petId}"
}
resource "aws_api_gateway_method" "petsMethodGet" {
  rest_api_id   = aws_api_gateway_rest_api.Api.id
  resource_id   = aws_api_gateway_resource.petsResource.id
  http_method   = "GET"
  authorization = "NONE"
}


resource "aws_api_gateway_method_response" "petsMethodResponseGet" {
    rest_api_id = aws_api_gateway_rest_api.Api.id 
    resource_id = aws_api_gateway_resource.petsResource.id
    http_method = aws_api_gateway_method.petsMethodGet.http_method 
    status_code ="200"
}

resource "aws_api_gateway_integration" "petsIntegration" {
  rest_api_id = aws_api_gateway_rest_api.Api.id
  resource_id = aws_api_gateway_resource.petsResource.id
  http_method = aws_api_gateway_method.petsMethodGet.http_method
  type        = "HTTP"
  
  uri                     = "http://petstore-demo-endpoint.execute-api.com/petstore/pets"
  integration_http_method = "GET"
  depends_on              = [aws_api_gateway_method.petsMethodGet]
}

resource "aws_api_gateway_integration_response" "petsIntegrationResponse" {
    rest_api_id = aws_api_gateway_rest_api.Api.id
    resource_id = aws_api_gateway_resource.petsResource.id
    http_method = aws_api_gateway_method.petsMethodGet.http_method
    status_code = aws_api_gateway_method_response.petsMethodResponseGet.status_code
}

resource "aws_api_gateway_method" "petIdMethodGet" {
    rest_api_id   = aws_api_gateway_rest_api.Api.id
    resource_id   = aws_api_gateway_resource.petIdResource.id
    http_method   = "GET"
    authorization = "NONE"
    request_parameters = {"method.request.path.petId" = true}
}

resource "aws_api_gateway_method_response" "petIdMethodResponseGet" {
    rest_api_id = aws_api_gateway_rest_api.Api.id 
    resource_id = aws_api_gateway_resource.petIdResource.id
    http_method = aws_api_gateway_method.petIdMethodGet.http_method 
    status_code ="200"
}


resource "aws_api_gateway_integration" "petIdIntegration" {
    rest_api_id = aws_api_gateway_rest_api.Api.id
    resource_id = aws_api_gateway_resource.petIdResource.id
    http_method = aws_api_gateway_method.petIdMethodGet.http_method
    type        = "HTTP"
    uri                     = "http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}"
    integration_http_method = "GET"
    request_parameters = {"integration.request.path.id" = "method.request.path.petId"}
    depends_on              = [aws_api_gateway_method.petIdMethodGet]
}

resource "aws_api_gateway_integration_response" "petIdIntegrationResponse" {
    rest_api_id = aws_api_gateway_rest_api.Api.id
    resource_id = aws_api_gateway_resource.petIdResource.id
    http_method = aws_api_gateway_method.petIdMethodGet.http_method
    status_code = aws_api_gateway_method_response.petIdMethodResponseGet.status_code
}


resource "aws_api_gateway_deployment" "Deployment" {
  rest_api_id = aws_api_gateway_rest_api.Api.id
  depends_on  = [aws_api_gateway_integration.petsIntegration,aws_api_gateway_integration.petIdIntegration ]
}
resource "aws_api_gateway_stage" "Stage" {
  stage_name    = "Prod"
  rest_api_id   = aws_api_gateway_rest_api.Api.id
  deployment_id = aws_api_gateway_deployment.Deployment.id
}
```

# Tutorial: Create a private REST API
<a name="private-api-tutorial"></a>

In this tutorial, you create a private REST API. Clients can access the API only from within your Amazon VPC. The API is isolated from the public internet, which is a common security requirement.

This tutorial takes approximately 30 minutes to complete. First, you use an CloudFormation template to create an Amazon VPC, a VPC endpoint, an AWS Lambda function, and launch an Amazon EC2 instance that you'll use to test your API. Next, you use the AWS Management Console to create a private API and attach a resource policy that allows access only from your VPC endpoint. Lastly, you test your API. 

![\[Overview of the private API you create in this tutorial.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/private-api-tutorial-diagram.png)


To complete this tutorial, you need an AWS account and an AWS Identity and Access Management user with console access. For more information, see [Set up to use API Gateway](setting-up.md).

In this tutorial, you use the AWS Management Console. For an CloudFormation template that creates this API and all related resources, see [template.yaml](samples/private-api-full-template.zip).

**Topics**
+ [

## Step 1: Create dependencies
](#private-api-tutorial-create-dependencies)
+ [

## Step 2: Create a private API
](#private-api-tutorial-create-api)
+ [

## Step 3: Create a method and integration
](#private-api-tutorial-create-method)
+ [

## Step 4: Attach a resource policy
](#private-api-tutorial-attach-resource-policy)
+ [

## Step 5: Deploy your API
](#private-api-tutorial-deploy-api)
+ [

## Step 6: Verify that your API isn't publicly accessible
](#private-api-tutorial-test-private-api)
+ [

## Step 7: Connect to an instance in your VPC and invoke your API
](#private-api-tutorial-connect-to-instance)
+ [

## Step 8: Clean up
](#private-api-tutorial-cleanup)
+ [

## Next steps: Automate with CloudFormation
](#private-api-tutorial-next-steps)

## Step 1: Create dependencies
<a name="private-api-tutorial-create-dependencies"></a>

Download and unzip [this CloudFormation template](samples/private-api-starter-template.zip). You use the template to create all of the dependencies for your private API, including an Amazon VPC, a VPC endpoint, and a Lambda function that serves as the backend of your API. You create the private API later.

**To create an CloudFormation stack**

1. Open the CloudFormation console at [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/).

1. Choose **Create stack** and then choose **With new resources (standard)**.

1. For **Specify template**, choose **Upload a template file**.

1. Select the template that you downloaded.

1. Choose **Next**. 

1. For **Stack name**, enter **private-api-tutorial** and then choose **Next**.

1. For **Configure stack options**, choose **Next**.

1. For **Capabilities**, acknowledge that CloudFormation can create IAM resources in your account.

1. Choose **Next**, and then choose **Submit**.

CloudFormation provisions the dependencies for your API, which can take a few minutes. When the status of your CloudFormation stack is **CREATE\$1COMPLETE**, choose **Outputs**. Note your VPC endpoint ID. You need it for later steps in this tutorial. 

## Step 2: Create a private API
<a name="private-api-tutorial-create-api"></a>

You create a private API to allow only clients within your VPC to access it.

**To create a private API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose **Create API**, and then for **REST API**, choose **Build**.

1. For **API name**, enter **private-api-tutorial**.

1. For **API endpoint type**, select **Private**.

1. For **VPC endpoint IDs**, enter the VPC endpoint ID from the **Outputs** of your CloudFormation stack.

1. For **IP address type**, choose **Dualstack**.

1. Choose **Create API**.

## Step 3: Create a method and integration
<a name="private-api-tutorial-create-method"></a>

You create a `GET` method and Lambda integration to handle `GET` requests to your API. When a client invokes your API, API Gateway sends the request to the Lambda function that you created in Step 1, and then returns a response to the client.

**To create a method and integration**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose your API.

1. Choose **Create method**.

1. For **Method type** select `GET`.

1. For **Integration type**, select **Lambda function**.

1. Turn on **Lambda proxy integration**. With a Lambda proxy integration, API Gateway sends an event to Lambda with a defined structure, and transforms the response from your Lambda function to an HTTP response.

1. For **Lambda function**, choose the function that you created with the CloudFormation template in Step 1. The function's name begins with **private-api-tutorial**.

1. Choose **Create method**.

## Step 4: Attach a resource policy
<a name="private-api-tutorial-attach-resource-policy"></a>

You attach a [resource policy](apigateway-resource-policies.md) to your API that allows clients to invoke your API only through your VPC endpoint. To further restrict access to your API, you can also configure a [ VPC endpoint policy](apigateway-vpc-endpoint-policies.md) for your VPC endpoint, but that's not necessary for this tutorial.

**To attach a resource policy**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose your API.

1. Choose **Resource policy**, and then choose **Create policy**.

1. Enter the following policy. Replace *vpceID* with your VPC endpoint ID from the **Outputs** of your CloudFormation stack.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Deny",
               "Principal": "*",
               "Action": "execute-api:Invoke",
               "Resource": "execute-api:/*",
               "Condition": {
                   "StringNotEquals": {
                       "aws:sourceVpce": "vpce-abcd1234"
                   }
               }
           },
           {
               "Effect": "Allow",
               "Principal": "*",
               "Action": "execute-api:Invoke",
               "Resource": "execute-api:/*"
           }
       ]
   }
   ```

------

1. Choose **Save changes**.

## Step 5: Deploy your API
<a name="private-api-tutorial-deploy-api"></a>

Next, you deploy your API to make it available to clients in your Amazon VPC.

**To deploy an API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose your API.

1. Choose **Deploy API**.

1. For **Stage**, select **New stage**.

1. For **Stage name**, enter **test**.

1. (Optional) For **Description**, enter a description.

1. Choose **Deploy**.

Now you're ready to test your API.

## Step 6: Verify that your API isn't publicly accessible
<a name="private-api-tutorial-test-private-api"></a>

Use `curl` to verify that you can't invoke your API from outside of your Amazon VPC.

**To test your API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose your API.

1. In the main navigation pane, choose **Stages**, and then choose the **test** stage.

1. Under **Stage details**, choose the copy icon to copy your API's invoke URL. The URL looks like `https://abcdef123.execute-api.us-west-2.amazonaws.com/test`. The VPC endpoint that you created in Step 1 has private DNS enabled, so you can use the provided URL to invoke your API.

1. Use curl to attempt to invoke your API from outside of your VPC.

   ```
   curl https://abcdef123.execute-api.us-west-2.amazonaws.com/test
   ```

   Curl indicates that your API's endpoint can't be resolved. If you get a different response, go back to Step 2, and make sure that you choose **Private** for your API's endpoint type.

   ```
   curl: (6) Could not resolve host: abcdef123.execute-api.us-west-2.amazonaws.com/test
   ```

Next, you connect to an Amazon EC2 instance in your VPC to invoke your API.

## Step 7: Connect to an instance in your VPC and invoke your API
<a name="private-api-tutorial-connect-to-instance"></a>

Next, you test your API from within your Amazon VPC. To access your private API, you connect to an Amazon EC2 instance in your VPC and then use curl to invoke your API. You use Systems Manager Session Manager to connect to your instance in the browser.

**To test your API**

1. Open the Amazon EC2 console at [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/).

1. Choose **Instances**.

1. Choose the instance named **private-api-tutorial** that you created with the CloudFormation template in Step 1.

1. Choose **Connect** and then choose **Session Manager**.

1. Choose **Connect** to launch a browser-based session to your instance.

1. In your Session Manager session, use curl to invoke your API. You can invoke your API because you're using an instance in your Amazon VPC.

   ```
   curl https://abcdef123.execute-api.us-west-2.amazonaws.com/test
   ```

   Verify that you get the response `Hello from Lambda!`.

![\[You use Session Manager to invoke your API from within your Amazon VPC.\]](http://docs.aws.amazon.com/apigateway/latest/developerguide/images/private-api-tutorial-invoke.png)


You successfully created an API that's accessible only from within your Amazon VPC and then verified that it works.

## Step 8: Clean up
<a name="private-api-tutorial-cleanup"></a>

To prevent unnecessary costs, delete the resources that you created as part of this tutorial. The following steps delete your REST API and your CloudFormation stack.

**To delete a REST API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. On the **APIs** page, select an API. Choose **API actions**, choose **Delete API**, and then confirm your choice.

**To delete an CloudFormation stack**

1. Open the CloudFormation console at [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/).

1. Select your CloudFormation stack.

1. Choose **Delete** and then confirm your choice.

## Next steps: Automate with CloudFormation
<a name="private-api-tutorial-next-steps"></a>

You can automate the creation and cleanup of all AWS resources involved in this tutorial. For a full example CloudFormation template, see [template.yaml](samples/private-api-full-template.zip).