jets
jets copied to clipboard
Missing API Methods leads to 500 errors
I am not 100% sure if this is an config issue on my side.
Checklist
- [ 👍 ] Upgrade Jets: Are you using the latest version of Jets? This allows Jets to fix issues fast. There's a
jets upgrade
command that makes this a simple task. There's also an Upgrading Guide: http://rubyonjets.com/docs/upgrading/ - [👍 ] Reproducibility: Are you reporting a bug others will be able to reproduce and not asking a question. If you're unsure or want to ask a question, do so on https://community.boltops.com
- [ ] Code sample: Have you put together a code sample to reproduce the issue and make it available? Code samples help speed up fixes dramatically. If it's an easily reproducible issue, then code samples are not needed. If you're unsure, please include a code sample.
My Environment
Software | Version |
---|---|
Operating System | OSX 14.0 |
Jets | 5.0.8 |
Ruby | 3.2.2 |
Expected Behaviour
Routes map to controller lambda via lambda proxy
Current Behavior
I have created a brand new jets project on 5.0.8. I have a few different controller methods using GET/PUT/POST,etc. When deploying, only a get catachall seems to be created on API gateway
Step-by-step reproduction instructions
Create a clean jets 5.0.8 project, add a model and crud methods, deploy.
Code Sample
Output from jets routes:
+--------------------+---------+-------------------------------------+--------------------------+
| As (Prefix) | Verb | Path (URI Pattern) | Controller#action |
+--------------------+---------+-------------------------------------+--------------------------+
| health | GET | /health | health#health |
| v1_sources | GET | /v1/sources | v1/sources#index |
| v1_sources | POST | /v1/sources | v1/sources#create |
| v1_source | GET | /v1/sources/:id | v1/sources#show |
| v1_source | PUT | /v1/sources/:id | v1/sources#update |
| v1_source | PATCH | /v1/sources/:id | v1/sources#update |
| v1_source_channels | GET | /v1/sources/:source_id/channels | v1/channels#index |
| v1_source_channels | POST | /v1/sources/:source_id/channels | v1/channels#create |
| v1_source_channel | GET | /v1/sources/:source_id/channels/:id | v1/channels#show |
| v1_source_channel | PUT | /v1/sources/:source_id/channels/:id | v1/channels#update |
| v1_source_channel | PATCH | /v1/sources/:source_id/channels/:id | v1/channels#update |
| v1_account_sources | GET | /v1/account_sources | v1/account_sources#index |
| v1_account_source | GET | /v1/account_sources/:id | v1/account_sources#show |
| v1_insights | GET | /v1/insights | v1/insights#index |
| | OPTIONS | /*catchall | cors#preflight |
+--------------------+---------+-------------------------------------+--------------------------+
API Gateway Resources:
/
GET
/{+catchall}
ApiMethod template:
Resources:
AnyCatchallApiMethod:
Type: AWS::ApiGateway::Method
Properties:
ResourceId: !Ref CatchallApiResource
RestApiId: !Ref RestApi
HttpMethod: GET
RequestParameters: {}
AuthorizationType: NONE
ApiKeyRequired: 'false'
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${JetsControllerLambdaFunction}/invocations
MethodResponses: []
Parameters:
RestApi:
Type: String
JetsControllerLambdaFunction:
Type: String
CatchallApiResource:
Type: String
I have found the culprit, I have a custom catchall method in my routes for options as this endpoint is doing some custom cors stuff:
def ensure_one_apigw_method_proxy_routes!
return unless Jets.config.cfn.build.routes == "one_apigw_method_for_all_routes"
# find before modifications
catchall_route = Jets::Router.routes.find { |route| route.path =~ /^\/\*/ }
root_route = Jets::Router.routes.find { |route| route.http_method == "GET" && route.path == "/" }
# modifications
unless catchall_route
# Note: catchall to route does not matter. In one_apigw_method_for_all_routes mode it all goes to one lambda function
# and then gets routed by config/routes.rb
Jets::Router.routes << Jets::Router::Route.new(path: '/*catchall', http_method: 'ANY', to: 'jets/public#show')
end
if !root_route && catchall_route
Jets::Router.routes << Jets::Router::Route.new(path: '/', http_method: 'GET', to: catchall_route.to)
end
end
This creates a get catchall if any route method catchall exist. even in my situation where the catchall is only for options.
I can make a PR to update this, but want to make sure I am not missing anything first.
Current monkey patch that seems to be working:
When I get a few moments of free time ill create a MR
module Jets::Cfn::Builder::Api
class Methods < Paged
...
def ensure_one_apigw_method_proxy_routes!
return unless Jets.config.cfn.build.routes == "one_apigw_method_for_all_routes"
# find before modifications
catchall_routes = Jets::Router.routes.select { |route| route.path =~ /^\/\*/ }
ensure_root_route!(catchall_routes)
# find after modifications
# only add catchall route if it does not exist for the any method.
unless catchall_routes.detect { |route| route.http_method == "ANY" }.present?
# Note: catchall to route does not matter. In one_apigw_method_for_all_routes mode it all goes to one lambda function
# and then gets routed by config/routes.rb
Jets::Router.routes << Jets::Router::Route.new(path: '/*catchall', http_method: 'ANY', to: 'jets/public#show')
end
end
# If the root route is missing, add it. This is how it works locally.
# The GET catchall route should take precedence over the ANY catchall route.
def ensure_root_route!(catchall_routes = [])
root_route = Jets::Router.routes.find { |route| route.http_method == "GET" && route.path == "/" }
return if root_route || catchall_routes.empty?
root_catchall = catchall_routes.detect { |route| route.http_method == "GET" }
root_catchall = catchall_routes.detect { |route| route.http_method == "GET" } unless root_catchall
return unless root_catchall
Jets::Router.routes << Jets::Router::Route.new(path: '/', http_method: 'GET', to: root_catchall.to)
end
end
end