title: AWS Api Gateway proxy resource using Cloudformation?
body: <p>I'm trying to proxy an S3 bucket configured as a website from an API Gateway endpoint. I configured an endpoint successfully using the console, but I am unable to recreate the configuration using Cloudformation.</p>
  
  <p>After lots of trial and error and guessing, I've come up with the following CF stack template that gets me pretty close:</p>
  
  <pre><code>Resources:
    Api:
      Type: 'AWS::ApiGateway::RestApi'
      Properties:
        Name: ApiDocs
  
    Resource:
      Type: 'AWS::ApiGateway::Resource'
      Properties:
        ParentId: !GetAtt Api.RootResourceId
        RestApiId: !Ref Api
        PathPart: '{proxy+}'
  
    RootMethod:
      Type: 'AWS::ApiGateway::Method'
      Properties:
        HttpMethod: ANY
        ResourceId: !GetAtt Api.RootResourceId
        RestApiId: !Ref Api
        AuthorizationType: NONE
        Integration:
          IntegrationHttpMethod: ANY
          Type: HTTP_PROXY
          Uri: 'http://my-bucket.s3-website-${AWS::Region}.amazonaws.com/'
          PassthroughBehavior: WHEN_NO_MATCH
          IntegrationResponses:
            - StatusCode: 200
  
    ProxyMethod:
      Type: 'AWS::ApiGateway::Method'
      Properties:
        HttpMethod: ANY
        ResourceId: !Ref Resource
        RestApiId: !Ref Api
        AuthorizationType: NONE
        RequestParameters:
          method.request.path.proxy: true
        Integration:
          CacheKeyParameters:
            - 'method.request.path.proxy'
          RequestParameters:
            integration.request.path.proxy: 'method.request.path.proxy'
          IntegrationHttpMethod: ANY
          Type: HTTP_PROXY
          Uri: 'http://my-bucket.s3-website-${AWS::Region}.amazonaws.com/{proxy}'
          PassthroughBehavior: WHEN_NO_MATCH
          IntegrationResponses:
            - StatusCode: 200
  
    Deployment:
      DependsOn:
        - RootMethod
        - ProxyMethod
      Type: 'AWS::ApiGateway::Deployment'
      Properties:
        RestApiId: !Ref Api
        StageName: dev
  </code></pre>
  
  <p>Using this template I can successfully get the root of the bucket website, but the proxy resource gives me a 500:</p>
  
  <pre><code>curl -i https://abcdef.execute-api.eu-west-1.amazonaws.com/dev/index.html
  HTTP/1.1 500 Internal Server Error
  Content-Type: application/json
  Content-Length: 36
  Connection: keep-alive
  Date: Mon, 11 Dec 2017 16:36:02 GMT
  x-amzn-RequestId: 6014a809-de91-11e7-95e4-dda6e24d156a
  X-Cache: Error from cloudfront
  Via: 1.1 8f6f9aba914cc74bcbbf3c57e10df26a.cloudfront.net (CloudFront)
  X-Amz-Cf-Id: TlOCX3eemHfY0aiVk9MLCp4qFzUEn5I0QUTIPkh14o6-nh7YAfUn5Q==
  
  {"message": "Internal server error"}
  </code></pre>
  
  <p>I have no idea how to debug that 500.</p>
  
  <p>To track down what may be wrong, I've compared the output of <code>aws apigateway get-resource</code> on the resource I created manually in the console (which is working) with the one Cloudformation made (which isn't). The resources look exactly alike. The output of <code>get-method</code> however, is subtly different, and I'm not sure it's possible to make them exactly the same using Cloudformation.</p>
  
  <p>Working method configuration:</p>
  
  <pre><code>{
    "apiKeyRequired": false,
    "httpMethod": "ANY",
    "methodIntegration": {
      "integrationResponses": {
        "200": {
          "responseTemplates": {
            "application/json": null
          },
          "statusCode": "200"
        }
      },
      "passthroughBehavior": "WHEN_NO_MATCH",
      "cacheKeyParameters": [
        "method.request.path.proxy"
      ],
      "requestParameters": {
        "integration.request.path.proxy": "method.request.path.proxy"
      },
      "uri": "http://muybucket.s3-website-eu-west-1.amazonaws.com/{proxy}",
      "httpMethod": "ANY",
      "cacheNamespace": "abcdefg",
      "type": "HTTP_PROXY"
    },
    "requestParameters": {
      "method.request.path.proxy": true
    },
    "authorizationType": "NONE"
  }
  </code></pre>
  
  <p>Configuration that doesn't work:</p>
  
  <pre><code>{
      "apiKeyRequired": false,
      "httpMethod": "ANY",
      "methodIntegration": {
          "integrationResponses": {
              "200": {
                  "responseParameters": {},
                  "responseTemplates": {},
                  "statusCode": "200"
              }
          },
          "passthroughBehavior": "WHEN_NO_MATCH",
          "cacheKeyParameters": [
              "method.request.path.proxy"
          ],
          "requestParameters": {
              "integration.request.path.proxy": "method.request.path.proxy"
          },
          "uri": "http://mybucket.s3-website-eu-west-1.amazonaws.com/{proxy}",
          "httpMethod": "ANY",
          "requestTemplates": {},
          "cacheNamespace": "abcdef",
          "type": "HTTP_PROXY"
      },
      "requestParameters": {
          "method.request.path.proxy": true
      },
      "requestModels": {},
      "authorizationType": "NONE"
  }
  </code></pre>
  
  <p>The differences:</p>
  
  <ul>
  <li>The working configuration has <code>responseTemplates</code> set to <code>"application/json": null</code>. As far as I can tell, there's no way to set a mapping explicitly to <code>null</code> using Cloudformation. My CF method instead just has an empty object here.</li>
  <li>My CF method has <code>"responseParameters": {},</code>, while the working configuration does not have <code>responseParameters</code> at all</li>
  <li>My CF method has <code>"requestModels": {},</code>, while the working configuration does not have <code>requestModels</code> at all</li>
  </ul>
  
  <p>Comparing the two in the console, they are seemingly exactly the same.</p>
  
  <p>I'm at my wits end here: what am I doing wrong? Is this possible to achieve using Cloudformation?</p>