{"id":13878939,"url":"https://github.com/amancevice/yake","last_synced_at":"2025-05-15T23:08:22.607Z","repository":{"id":43199053,"uuid":"361853688","full_name":"amancevice/yake","owner":"amancevice","description":"A Rake-like DSL for writing AWS Lambda handlers","archived":false,"fork":false,"pushed_at":"2025-03-16T14:35:35.000Z","size":205,"stargazers_count":172,"open_issues_count":0,"forks_count":7,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-12T22:48:47.247Z","etag":null,"topics":["api-gateway","aws","datadog","dsl","lambda","rake","ruby","serverless"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/amancevice.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-26T18:27:27.000Z","updated_at":"2025-04-23T13:20:52.000Z","dependencies_parsed_at":"2023-02-01T01:31:04.104Z","dependency_job_id":"398d72c6-9abb-4013-b008-375d47035458","html_url":"https://github.com/amancevice/yake","commit_stats":{"total_commits":147,"total_committers":2,"mean_commits":73.5,"dds":0.006802721088435382,"last_synced_commit":"f044245cf6ae809d9a3a0987362f9bd896a8219c"},"previous_names":[],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amancevice%2Fyake","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amancevice%2Fyake/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amancevice%2Fyake/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amancevice%2Fyake/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amancevice","download_url":"https://codeload.github.com/amancevice/yake/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254436949,"owners_count":22070947,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-gateway","aws","datadog","dsl","lambda","rake","ruby","serverless"],"created_at":"2024-08-06T08:02:04.777Z","updated_at":"2025-05-15T23:08:15.661Z","avatar_url":"https://github.com/amancevice.png","language":"Ruby","readme":"# λake\n\n[![gem](https://img.shields.io/gem/v/yake?color=crimson\u0026logo=rubygems\u0026logoColor=eee\u0026style=flat-square)](https://rubygems.org/gems/yake)\n[![rspec](https://img.shields.io/github/actions/workflow/status/amancevice/yake/rspec.yml?logo=github\u0026style=flat-square)](https://github.com/amancevice/yake/actions/workflows/rspec.yml)\n[![coverage](https://img.shields.io/codeclimate/coverage/amancevice/yake?logo=code-climate\u0026style=flat-square)](https://codeclimate.com/github/amancevice/yake/test_coverage)\n[![maintainability](https://img.shields.io/codeclimate/maintainability/amancevice/yake?logo=code-climate\u0026style=flat-square)](https://codeclimate.com/github/amancevice/yake/maintainability)\n\n[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/smallweirdnumber)\n\nWrite your AWS Lambda function handlers using a Rake-like declarative syntax:\n\n```ruby\n# ./lambda_function.rb\nrequire 'yake'\n\nhandler :lambda_handler do |event|\n  # Your code here\nend\n\n# Handler signature: `lambda_function.lambda_handler`\n```\n\nYou can even declare Sinatra-like API Gateway routes for a main entrypoint:\n\n```ruby\n# ./lambda_function.rb\nrequire 'yake/api'\n\nheader 'content-type' =\u003e 'application/json'\n\nget '/fizz' do\n  respond 200, { ok: true }.to_json\nend\n\nhandler :lambda_handler do |event|\n  route event\nrescue =\u003e err\n  respond 500, { message: err.message }.to_json\nend\n\n# Handler signature: `lambda_function.lambda_handler`\n```\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'yake'\n```\n\nAnd then execute:\n\n```bash\nbundle install\n```\n\nOr install it yourself as:\n\n```bash\ngem install yake\n```\n\n## Why Is It Called \"yake\"?\n\n\"λ\" + Rake, but \"λ\" is hard to type and I think \"y\" looks like a funny little upside-down-and-backwards Lambda symbol.\n\n## Why Use It?\n\nSo why use `yake` for your Lambda functions?\n\n### Event Logging\n\nBy default, the `handler` function wraps its block in log lines formatted to match the style of Amazon's native Lambda logs sent to CloudWatch. Each invocation of the handler will log both the _input event_ and the _returned value_, prefixed with the ID of the request:\n\n```plaintext\nSTART RequestId: 149c500f-028a-4b57-8977-0ef568cf8caf Version: $LATEST\nINFO RequestId: 149c500f-028a-4b57-8977-0ef568cf8caf EVENT { … }\n…\nINFO RequestId: 149c500f-028a-4b57-8977-0ef568cf8caf RETURN { … }\nEND RequestId: 149c500f-028a-4b57-8977-0ef568cf8caf\nREPORT RequestId: 149c500f-028a-4b57-8977-0ef568cf8caf  Duration: 43.97 ms  Billed Duration: 44 ms  Memory Size: 128 MB  Max Memory Used: 77 MB\n```\n\nLogging the request ID in this way makes gathering logs lines for a particular execution in CloudWatch much easier.\n\nYou can customize or disable the logger:\n\n```ruby\nlogging :off              # disables logging entirely\nlogging pretty: false     # Logs event/result in compact JSON\nlogging :on, MyLogger.new # Use a custom logger\n```\n\nInclude `Yake::Logger` on a class to access this logger:\n\n```ruby\nclass Fizz\n  include Yake::Logger\nend\n\nFizz.new.logger == Yake.logger\n# =\u003e true\n```\n\n### API Routes\n\nA common use of Lambda functions is as a proxy for API Gateway. Oftentimes users will deploy a single Lambda function to handle all requests coming from API Gateway.\n\nRequiring the `yake/api` module will add the API-specific DSL into your handler.\n\nDefine API routes using Sinatra-like syntax\n\n```ruby\nany '/…' do |event|\n  # Handle 'ANY /…' route key events\nend\n\ndelete '/…' do |event|\n  # Handle 'DELETE /…' route key events\nend\n\nget '/…' do |event|\n  # Handle 'GET /…' route key events\nend\n\nhead '/…' do |event|\n  # Handle 'HEAD /…' route key events\nend\n\noptions '/…' do |event|\n  # Handle 'OPTIONS /…' route key events\nend\n\npatch '/…' do |event|\n  # Handle 'PATCH /…' route key events\nend\n\npost '/…' do |event|\n  # Handle 'POST /…' route key events\nend\n\nput '/…' do |event|\n  # Handle 'PUT /…' route key events\nend\n```\n\nHelper methods are also made available to help produce a response for API Gateway:\n\nSet a default header for ALL responses:\n\n```ruby\nheader 'content-type' =\u003e 'application/json; charset=utf-8'\nheader 'x-custom-header' =\u003e 'fizz'\n```\n\nProduce an API Gateway-style response object:\n\n```ruby\nrespond 200, { ok: true }.to_json, 'x-extra-header' =\u003e 'buzz'\n# {\n#   \"statusCode\" =\u003e 200,\n#   \"body\" =\u003e '{\"ok\":true}',\n#   \"headers\" =\u003e { \"x-extra-header\" =\u003e \"buzz\" }\n# }\n```\n\nRoute an event to one of the declared routes:\n\n```ruby\nhandler :lambda_handler do |event|\n  route event\nrescue Yake::Errors::UndeclaredRoute =\u003e err\n  respond 404, { message: err.message }.to_json\nrescue =\u003e err\n  respond 500, { message: err.message }.to_json\nend\n```\n\n### (Near) Zero Dependencies\n\nFinally, `yake` does not depend on any 3rd party gems. The only exceptions are the `ostruct` and `logger` gems, which are being removed from the Ruby stdlib in Ruby v3.5. This helps keep your Lambda packages slim \u0026 speedy.\n\n## Support Helpers\n\nAs of `~\u003e 0.5`, `yake` comes with a support module for common transformations.\n\nEnable the helpers by requiring the `support` submodule:\n\n```ruby\nrequire 'yake/support'\n```\n\n`Array` helpers:\n\n```ruby\narray = [{ a: 'b'}, { a: 'c' }, { a: 'd' }]\n\narray.pluck(:a)\n# =\u003e [\"b\", \"c\", \"d\"]\n\narray.to_dynamodb\n# =\u003e {:L=\u003e[{:a=\u003e{:S=\u003e\"b\"}}, {:a=\u003e{:S=\u003e\"c\"}}, {:a=\u003e{:S=\u003e\"d\"}}]}\n```\n\n`Object` helpers:\n\n```ruby\nMyObject.new.some_method\n# =\u003e NoMethodError\n\nMyObject.new.try(:some_method)\n# =\u003e nil\n\n10.try(:some_method) { |x| x ** 2 }\n# =\u003e 100\n```\n\n`Hash` helpers:\n\n```ruby\n{ a: { b: 'c', d: 'e' }, f: 'g' }.deep_keys\n# =\u003e [:a, :b, :d, :f]\n\nleft  = { a: 'b', c: { d: %w[e] } }\nright = { a: 'a', c: { d: %w[d] } }\nleft.deep_merge(right)\n# =\u003e { :a =\u003e \"a\", :c =\u003e { :d =\u003e [\"e\", \"d\"] } }\n\n{ a: { b: 'c', d: 'e' }, f: 'g' }.deep_transform_keys(\u0026:to_s)\n# =\u003e { \"a\" =\u003e { \"b\" =\u003e \"c\", \"d\" =\u003e \"e\" }, \"f\" =\u003e \"g\" }\n\nhash = { a: { b: 'c', d: 'e' }, f: 'g' }\nhash.deep_transform_keys!(\u0026:to_s)\n# =\u003e { \"a\" =\u003e { \"b\" =\u003e \"c\", \"d\" =\u003e \"e\" }, \"f\" =\u003e \"g\" }\n\n{ f: 'g', a: { d: 'e', b: 'c' } }.deep_sort\n# =\u003e { a: { b: 'c', d: 'e' }, f: 'g' }\n\n{ fizz: 'buzz' }.encode64\n# =\u003e \"eyJmaXp6IjoiYnV6eiJ9\\n\"\n\n{ fizz: 'buzz', jazz: 'fuzz' }.except(:buzz)\n# =\u003e { :fizz =\u003e 'buzz' }\n\n{ fizz: 'buzz' }.strict_encode64\n# =\u003e \"eyJmaXp6IjoiYnV6eiJ9\"\n\n{ fizz: { buzz: %w[jazz fuzz] } }.stringify_names\n# =\u003e { \"fizz\" =\u003e { \"buzz\" =\u003e [\"jazz\", \"fuzz\"] } }\n\n{ 'fizz' =\u003e { 'buzz' =\u003e %w[jazz fuzz] } }.symbolize_names\n# =\u003e { :fizz =\u003e { :buzz =\u003e [\"jazz\", \"fuzz\"] } }\n\n{ fizz: 'buzz' }.to_form\n# =\u003e \"fizz=buzz\"\n\n{ f: 'g', a: { d: 'e', b: 'c' } }.to_json_sorted\n# =\u003e '{\"a\":{\"b\":\"c\",\"d\":\"e\"},\"f\":\"g\"}'\n\n{ f: 'g', a: { d: 'e', b: 'c' } }.to_struct\n# =\u003e #\u003cstruct f=\"g\", a={:d=\u003e\"e\", :b=\u003e\"c\"}\u003e\n\n{ f: 'g', a: { d: 'e', b: 'c' } }.to_deep_struct\n# =\u003e #\u003cstruct f=\"g\", a=#\u003cstruct d=\"e\", b=\"c\"\u003e\u003e\n\n{ a: { b: 'c', d: 'e' }, f: 'g' }.to_dynamodb\n# =\u003e { :a =\u003e { :M =\u003e { :b =\u003e { :S =\u003e \"c\" }, :d =\u003e { :S =\u003e \"e\" } } }, :f =\u003e { :S =\u003e \"g\" } }\n\n{ a: { M: { b: { S: 'c' }, d: { S: 'e' } } }, f: { S: 'g' } }.to_h_from_dynamodb\n# =\u003e { :a =\u003e { :b =\u003e \"c\", :d =\u003e \"e\" }, :f =\u003e \"g\" }\n```\n\n`Integer` helpers:\n\n```ruby\n7.weeks\n# =\u003e 4_233_600\n\n7.days\n# =\u003e 604_800\n\n7.hours\n# =\u003e 25_200\n\n7.minutes\n# =\u003e 420\n\n1234567890.utc\n# =\u003e 2009-02-13 23:31:30 UTC\n```\n\n`String` helpers:\n\n```ruby\nhost = 'https://example.com/'\npath = '/path/to/resource'\nhost / path\n# =\u003e \"https://example.com/path/to/resource\"\n\n'snake_case_string'.camel_case\n# =\u003e \"SnakeCaseString\"\n\n\"Zml6eg==\\n\".decode64\n# =\u003e \"fizz\"\n\n'fizz'.encode64\n# =\u003e \"Zml6eg==\\n\"\n\n'fizz'.md5sum\n# =\u003e \"b6bfa6c318811be022d4f73070597660\"\n\n'fizz'.sha1sum\n# =\u003e \"c25f5985f2ab63baeb2408a2d7dbc79d8f29d02f\"\n\n'CamelCaseString'.snake_case\n# =\u003e \"camel_case_string\"\n\n'Zml6eg=='.strict_decode64\n# =\u003e \"fizz\"\n\n'fizz'.strict_encode64\n# =\u003e \"Zml6eg==\"\n\n'{\"fizz\":\"buzz\"}'.to_h_from_json\n# =\u003e { \"fizz\" =\u003e \"buzz\" }\n\n'fizz=buzz'.to_h_from_form\n# =\u003e { \"fizz\" =\u003e \"buzz\" }\n\n'2009-02-13T23:31:30Z'.utc\n# =\u003e 2009-02-13 23:31:30 UTC\n```\n\n`Symbol` helpers\n\n```ruby\n:snake_case_symbol.camel_case\n# =\u003e :SnakeCaseSymbol\n\n:CamelCaseSymbol.snake_case\n# =\u003e :camel_case_symbol\n```\n\n`UTC` Time helpers\n\n```ruby\nUTC.at 1234567890\n# =\u003e 2009-02-13 23:31:30 UTC\n\nUTC.now\n# =\u003e 2022-02-26 13:57:07.860539 UTC\n```\n\n## Datadog Integration\n\nAs of `v1.0`, `yake` comes with a helper for writing Lambdas that integrate with Datadog's `datadog-lambda` gem.\n\nAs of `~\u003e 0.8`, `yake` uses the v2 Datadog Lambda gem.\n\nCreating a Lambda handler that wraps the Datadog tooling is easy:\n\n```ruby\nrequire 'aws-sdk-someservice'\nrequire 'yake/datadog'\n\n# Configure Datadog to use AWS tracing\nDatadog::Lambda.configure_apm { |c| c.tracing.instrument :aws }\n\ndatadog :handler do |event|\n  # …\nend\n```\n\n## Deployment\n\nAfter writing your Lambda handler code you can deploy it to AWS using any number of tools. I recommend the following tools:\n\n- [Terraform](https://www.terraform.io) — my personal favorite Infrastructure-as-Code tool\n- [AWS SAM](https://aws.amazon.com/serverless/sam/) — a great alternative with less configuration than Terraform\n- [Serverless](https://www.serverless.com) — Supposedly the most popular option, though I have not used it\n\n## Development\n\nAfter checking out the repo, run `bundle` to install dependencies. Then, run `rake spec` to run the tests.\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at [amancevice/yake](https://github.com/amancevice/yake).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","funding_links":["https://ko-fi.com/smallweirdnumber"],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famancevice%2Fyake","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famancevice%2Fyake","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famancevice%2Fyake/lists"}