CodeGenieApp / CodeGenieApp/serverless-express

Routing to root path does not work correctly when using nested API resources

Open
#377 0 comments 6 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
5.3k
Forks
676
PR merge metrics
No merged PRs in 30d

Description

First off, thanks for this great project!

I'm reporting an issue here I ran into when using API Gateway v1 with a proxy resource.

### Repro

I have defined a RestAPI resource triggered on a **nested** root path and subpaths under a `/v1/` path namespace. The SAM template looks like this:

```
Events:
ProxyApiRoot:
Type: Api
Properties:
RestApiId: !Ref ExpressApi
Path: /v1/
Method: ANY
ProxyApiGreedy:
Type: Api
Properties:
RestApiId: !Ref ExpressApi
Path: /v1/{proxy+}
Method: ANY
```

I also have a BasePathMapping defined nesting one level deeper, so the final root path for my app is `/routes/v1/`.

My express app has a handler defined for the root path:

```
router.get('/', (req, res) => { ... }
```

However a request to `/routes/v1/` returns a generic 404 from express. The request is routing correctly through API Gateway to my app, but once it gets to express it can't find a matching handler for the `/` path.

### Debugging

I added a handler for the catch-all route `*` and printed out the currentInvoke to try to track down the problem. I think I narrowed it down to this line:

https://github.com/vendia/serverless-express/blob/4ba9799a6573ea4227939001c3e49e07b75a35ea/src/event-sources/utils.js#L6-L7

The issue is that my request to `/routes/v1/` is being handled by ProxyApiRoot, not ProxyApiGreedy. Since ProxyApiRoot doesn't populate a value for event.pathParameters.proxy, the fallback event.path is used. But unlike pathParameters.proxy, event.path includes the _full path_ including the namespaces. So for a request to the root of my app, serverless-express is interpreting the path as `event.path == '/routes/v1'`, not `event.path == '/'`.

### Solution?

There may need to be more smarts added to `getPathWithQueryStringParams` for stripping out prefixes from the root path.

For example from printing out the currentInvoke I found:
* The base path part is available at `event.requestContext.customDomain.basePathMatched == 'routes'`
* The `v1` part is available at `event.resource = '/v1'`.

Perhaps these can be used to remove `/routes/v1` from the root path when event.pathParameters.proxy is not populated.

### Workaround

In the short term I found a workaround by avoiding root paths altogether. My SAM template now looks like:

```
ProxyApiGreedy:
Type: Api
Properties:
RestApiId: !Ref ExpressApi
Path: /{proxy+}
Method: ANY
```

and I mount all my express routes at v1 explicitly using `app.use('/v1', router)`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.