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

feat: Support Ruby handlers with :: in path definition #1218

Conversation

njyjn
Copy link
Contributor

@njyjn njyjn commented Apr 29, 2021

Description

This enhancement adds support for Ruby handlers that have namespace resolution operators (::) in their path definition, e.g. handler: 'src/lambdas/examples/hello.Hello::Handler.process', etc. This was officially mentioned in the AWS documentation (see below). Logic was preserved for existing scenarios (without ::) to reduce the risk of regression.

Without this enhancement, the following error message is triggered when the handler is invoked

offline: Failure: Command failed with exit code 1: ruby /PATH_TO_PROJECT/node_modules/serverless-offline/dist/lambda/handler-runner/ruby-runner/invoke.rb src/functions/source.LambdaFunctions::Handler process
~/.rbenv/versions/2.7.1/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require': cannot load such file -- ./src/functions/source.LambdaFunctions::Handler (LoadError)

This seems to be because the handler paths and names are not being split correctly. For such Ruby handlers, the name should have the resolution operator instead of the path. Support for this already seems to be built-in

# handler name is either a global method or a static method in a class
# my_method or MyModule::MyClass.my_method
handler_method, handler_class = handler_name.split(".").reverse
handler_class ||= "Kernel"

Motivation and Context

AWS officially demonstrates the use of handler methods within modules and classes. The specific example given is

module LambdaFunctions
  class Handler
    def self.process(event:,context:)
      "Hello!"
    end
  end
end

where the handler setting is source.LambdaFunctions::Handler.process. Since this is the entry point for many developers, it would be great if it is supported by serverless-offline.

For projects that implement a large number of handlers, it would be optimal to not pollute the Kernel private_method namespace if such handlers can be encapsulated into their own modules and classes.

Resolves #1031

How Has This Been Tested?

Unit tests were added in 4a6d0dc to validate this enhancement, as well as the original functionality that was left in tact.

In addition to the additional unit tests, I was able to use serverless-offline for Ruby handlers with and without namespace separators

"serverless.ts"

  functions: {
    hello: {
      environment: {
        GEM_PATH: 'vendor/bundle/ruby/2.7.0/',
      },
      handler: 'src/lambdas/examples/hello.Hello::Handler.process',
      events: [
        {
          http: {
            path: '/hello',
            method: 'post',
            request: {
              schema: {
                'application/json': "${file(schemas/examples/hello.json)}"
              },
            },
          }
        }
      ]
    },
    hello2: {
      environment: {
        GEM_PATH: 'vendor/bundle/ruby/2.7.0/',
      },
      handler: 'src/lambdas/examples/hello2.handler',
      events: [
        {
          http: {
            path: '/hello2',
            method: 'post',
            request: {
              schema: {
                'application/json': "${file(schemas/examples/hello2.json)}"
              },
            },
          }
        }
      ]
    }
  }
...

Built locally using package.json and compiled used Babel per the contribution guide.

Please let me know if you have any questions or if there is something I can improve on. Thanks!

Edit: Added more details on the current way serverless-offline is failing to invoke such handlers. Clarified that as long as the path string contains ::, the enhancement will take effect.

Screenshots (if appropriate):

@SirFixAL0t
Copy link

This feature would be really helpful for teams that have unit tests build around multiple lambda functions. Without handling handlers in classes, the alternative is having lambda handlers in the global scope which causes scope creep of some functions resulting in false positives and blocking issues for ruby lambdas.

Thanks!

Copy link
Collaborator

@pgrzesik pgrzesik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @njyjn for submitting this PR. It looks good, well done 🙇

@pgrzesik pgrzesik changed the title Support Ruby handlers with :: in path definition feat: Support Ruby handlers with :: in path definition Jun 1, 2021
@pgrzesik pgrzesik merged commit 3178501 into dherault:master Jun 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SLS runtime: Ruby with modules - cannot load such file
3 participants