Skip to content

Mountpath is incorrect when deployed as serverless express app. #1463

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

Closed
paulpilone opened this issue Feb 1, 2020 · 4 comments
Closed

Mountpath is incorrect when deployed as serverless express app. #1463

paulpilone opened this issue Feb 1, 2020 · 4 comments

Comments

@paulpilone
Copy link

I'm experimenting deploying parse-server and parse-dashboard as serverless express apps in AWS API Gateway/Lambda using the aws-serverless-express package. parse-server worked well but I ran into an issue with parse-dashboard.

API Gateway adds a stage value to the path of the API URL e.g. https://abc123-api.us-east-1.amazonaws.com/dev where dev is the API stage. Resources are then mapped as part of the path after 'dev'. In the Lambda handler I mount the the dashboard as an express app at /dashboard:

const dashboard = new ParseDashboard({...});
app.use('/dashboard', dashboard);

A request to https://abc123-api.us-east-1.amazonaws.com/dev/dashboard works for the initial request but fails when it tries to load the login bundle. This is because parse-dashboard/app.js:195 sets the script src to <script src="${mountPath}bundles/login.bundle.js"></script> which resolves to https://abc123-api.us-east-1.amazonaws.com/dashboard/bundles/login.bundle.js. This URL returns a 403 from API Gateway because it's missing the stage path. Since mountPath is based on where the app is mounted there's no way to know what the original API Gateway path might be.

I fixed this temporarily by adding an ENV variable that allows me to prepend a path to the "mountPath" in app.js but that feels hacky. It works though so if there aren't any other better ideas I could issue a PR for it.

I think there's a huge advantage to supporting deployments of parse-server and parse-dashboard as serverless apps in terms of cost and complexity. Would love to see if there's a better way to fix this issue and make serverless deployments a first class citizen.

@paulpilone paulpilone reopened this Feb 4, 2020
@davimacedo
Copy link
Member

What is the env var you are using? MOUNT_PATH? I think it is currently the only way. If you think it could have also a better way to do that please feel free to open a PR.

@paulpilone
Copy link
Author

paulpilone commented Feb 12, 2020

@davimacedo I can test again but I found that the MOUNT_PATH env var wouldn't work when using aws-serverless-express. I dug into this a little more today and I don't think it's necessarily a parse issue but rather an API Gateway/aws-serverless-express issue.

Looking at the aws-serverless-express source you see that it uses event.path to construct the path used to match mounted apps:

function getPathWithQueryStringParams (event) {
  return url.format({ pathname: event.path, query: event.queryStringParameters })
}

If you log the event object you see that path does not include the base path (in the case of {proxy+} the stage name) but requestContext.path does:

{
    "resource": "/{proxy+}",
    "path": "/dashboard/login",
    "httpMethod": "GET",
     ...
     "requestContext": {
        "resourceId": "fsly6p",
        "resourcePath": "/{proxy+}",
        "httpMethod": "GET",
        "extendedRequestId": "HwPI6E1VIAMF6-w=",
        "requestTime": "11/Feb/2020:22:33:54 +0000",
        "path": "/dev/dashboard/login",
        ...
     }
     ...
}

So for now I'm testing out rewriting the event object's path before proxying the request to my app server. For example in my app.js:

// Set up parse server and dashboard
...
app.use(`${STAGE}/parse`, parse);
app.use(`${STAGE}/dashboard`, dashboard);

const appServer = serverlessExpress.createServer(app);
module.exports.parse = (event, context) => {
  console.log(`Event: ${JSON.stringify(event)}`);
  
  event.path = `${event.requestContext.path}`;

  console.log(`Event after resetting path: ${JSON.stringify(event)}`);

  serverlessExpress.proxy(appServer, event, context);
} 

Initial testing shows this works for both the server and dashboard (I was also having issues saving files because parse server constructs the file URL using the mount path). I haven't tested thoroughly yet and I'm concerned it'll introduce an issue if I switch to a custom domain but for now it's a workaround to keep me going.

@davimacedo
Copy link
Member

Nice. Thanks for sharing your learnings. It would be great if you could write a doc or a blog post about how to setup parse and parse dashboard for serverless :)

@paulpilone
Copy link
Author

@davimacedo I'd be happy to! I'm in the process of trying to migrate my production app (from the old ElasticBeanstalk setup) over to as much of a serverless architecture as I can. If I get that working at a production level I'll definitely write something up since I think it has the potential to reduce costs while still using the Parse suite.

In the mean time I think this issue can be closed since - unless there is a better solution than using mount path in the dashboard and server - this really appears to be a side effect of how API Gateway and aws-serverless-express treat the base path when you're using {proxy+}.

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

No branches or pull requests

2 participants