Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

event.resource in catch-all route gets + changed to * #1431

Closed
jakub-g opened this issue May 18, 2022 · 4 comments · Fixed by #1524
Closed

event.resource in catch-all route gets + changed to * #1431

jakub-g opened this issue May 18, 2022 · 4 comments · Fixed by #1524
Labels

Comments

@jakub-g
Copy link

jakub-g commented May 18, 2022

Bug Report

Context

With AWS, it's possible to define wildcard / "catch-all" routes using /stuff/{wildcard+} syntax in YML file:

https://stackoverflow.com/questions/35773025/is-it-possible-to-use-wildcards-or-catch-all-paths-in-aws-api-gateway

Then path of the requested resource is available as event.resource in the handler.

Problem

The value of event.resource is different under serverless vs serverless-offline:

Expected: /stuff/{wildcard+} (matching YML entry; this is how serverless works)
Actual: /stuff/{wildcard*} (serverless-offline converts + to * for some reason 🤔 )

Sample Code

  • file: serverless.yml
functions:
  myfunc:
    events:
      - http:
          path: '/stuff/{wildcard+}'
          method: 'GET'
  • file: handler.js
exports.hello = async function hello(event) {
  return {
    body: JSON.stringify({ resource: event.resource }),
    statusCode: 200,
  }
}

Versions

This is not new, has been happening for a while, but I didn't report it before as I wanted to update all versions first

  • serverless version: 3.17.0 (happening with 2.x too)
  • serverless-offline version: 8.8.0 (happening with 7.x too)
  • node.js version: 14.19 or 16.15
  • OS: macOS 12.4
@dnalborczyk dnalborczyk added the bug label Jul 7, 2022
@dnalborczyk
Copy link
Collaborator

dnalborczyk commented Jul 7, 2022

thank you for reporting!

I haven't looked into this yet, but one possibility you are experiencing this issue is that * is being used by hapi (the underlying REST engine powering serverless-offline) to define wildcard routes. just a bad guess.

@Ankcorn
Copy link
Contributor

Ankcorn commented Jul 12, 2022

I ran into this working on an api gateway adapter

@Lilja created some event bodies comparing serverless offline to apigateway to verify this

Api Gateway Rest Api
{
  resource: '/leading/prefix/{proxy+}',
  path: '/leading/prefix/test/thing',
  httpMethod: 'GET',
  headers: {
    accept: '*/*',
    Host: 'censored',
    'User-Agent': 'curl/7.83.1',
    'X-Amzn-Trace-Id': 'Root=1-62cd6757-7259b8dd7b8f145033708acd',
    'X-Forwarded-For': 'censored',
    'X-Forwarded-Port': '443',
    'X-Forwarded-Proto': 'https'
  },
  multiValueHeaders: {
    accept: [ '*/*' ],
    Host: [ 'censored' ],
    'User-Agent': [ 'curl/7.83.1' ],
    'X-Amzn-Trace-Id': [ 'Root=1-62cd6757-7259b8dd7b8f145033708acd' ],
    'X-Forwarded-For': [ 'censored' ],
    'X-Forwarded-Port': [ '443' ],
    'X-Forwarded-Proto': [ 'https' ]
  },
  queryStringParameters: null,
  multiValueQueryStringParameters: null,
  pathParameters: { proxy: 'test/thing' },
  stageVariables: null,
  requestContext: {
    resourceId: 'censored',
    resourcePath: '/leading/prefix/{proxy+}',
    httpMethod: 'GET',
    extendedRequestId: 'VJ0VvFLiIAMFiOQ=',
    requestTime: '12/Jul/2022:12:21:43 +0000',
    path: '/dev/leading/prefix/test/thing',
    accountId: '328886342752',
    protocol: 'HTTP/1.1',
    stage: 'dev',
    domainPrefix: 'qtdldn2207',
    requestTimeEpoch: 1657628503765,
    requestId: 'ff7a0efa-97df-4a02-abee-cbaa1927c0a5',
    identity: {
      cognitoIdentityPoolId: null,
      accountId: null,
      cognitoIdentityId: null,
      caller: null,
      sourceIp: 'censored',
      principalOrgId: null,
      accessKey: null,
      cognitoAuthenticationType: null,
      cognitoAuthenticationProvider: null,
      userArn: null,
      userAgent: 'curl/7.83.1',
      user: null
    },
    domainName: 'censored',
    apiId: 'censored'
  },
  body: null,
  isBase64Encoded: false
}

Serverless Offline
{
  body: null,
  headers: {
    'content-type': 'application/json',
    Accept: '*/*',
    'User-Agent': 'node-fetch/1.0 (+https://github.com/bitinn/node-fetch)',
    'Accept-Encoding': 'gzip,deflate',
    Connection: 'close',
    Host: 'localhost:4050'
  },
  httpMethod: 'GET',
  isBase64Encoded: false,
  multiValueHeaders: {
    'content-type': [ 'application/json' ],
    Accept: [ '*/*' ],
    'User-Agent': [ 'node-fetch/1.0 (+https://github.com/bitinn/node-fetch)' ],
    'Accept-Encoding': [ 'gzip,deflate' ],
    Connection: [ 'close' ],
    Host: [ 'localhost:4050' ]
  },
  multiValueQueryStringParameters: { batch: [ '1' ], input: [ '{"0":{"name":"Erik"}}' ] },
  path: '/leading/prefix//greet',
  pathParameters: { proxy: '/greet' },
  queryStringParameters: { batch: '1', input: '{"0":{"name":"Erik"}}' },
  requestContext: {
    accountId: 'offlineContext_accountId',
    apiId: 'offlineContext_apiId',
    authorizer: {
      claims: undefined,
      scopes: undefined,
      principalId: 'offlineContext_authorizer_principalId'
    },
    domainName: 'offlineContext_domainName',
    domainPrefix: 'offlineContext_domainPrefix',
    extendedRequestId: 'cl5htiwtg0000h2tw6mh1cc7d',
    httpMethod: 'GET',
    identity: {
      accessKey: null,
      accountId: 'offlineContext_accountId',
      apiKey: 'offlineContext_apiKey',
      apiKeyId: 'offlineContext_apiKeyId',
      caller: 'offlineContext_caller',
      cognitoAuthenticationProvider: 'offlineContext_cognitoAuthenticationProvider',
      cognitoAuthenticationType: 'offlineContext_cognitoAuthenticationType',
      cognitoIdentityId: 'offlineContext_cognitoIdentityId',
      cognitoIdentityPoolId: 'offlineContext_cognitoIdentityPoolId',
      principalOrgId: null,
      sourceIp: '127.0.0.1',
      user: 'offlineContext_user',
      userAgent: 'node-fetch/1.0 (+https://github.com/bitinn/node-fetch)',
      userArn: 'offlineContext_userArn'
    },
    operationName: undefined,
    path: '/leading/prefix//greet',
    protocol: 'HTTP/1.1',
    requestId: 'cl5htiwtg0001h2tw3l8w3l98',
    requestTime: '12/Jul/2022:08:54:33 +0200',
    requestTimeEpoch: 1657608873887,
    resourceId: 'offlineContext_resourceId',
    resourcePath: '/dev/leading/prefix/{proxy*}',
    stage: 'dev'
  },
  resource: '/leading/prefix/{proxy*}',
  stageVariables: null
}

I think its related to this line here

const resource = this.#routeKey || route.path.replace(`/${this.#stage}`, '')

Is this the fix

const resource = this.#routeKey || route.path.replace(`/${this.#stage}`, '').replace('*','+')

@Ankcorn
Copy link
Contributor

Ankcorn commented Jul 26, 2022

Hey @dnalborczyk if I made a PR with that fix do you think it would be merged?

@dnalborczyk
Copy link
Collaborator

Hey @dnalborczyk if I made a PR with that fix do you think it would be merged?

@Ankcorn that would be great. I don't see why not!?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants