This is my capstone project for school. It’s a file sharing service that stores files temporarily so they can be shared with friends. It’s very useful for sending files when you don’t want to spend the time to upload the files to GDrive or Office. The page instantly lets you upload many files.
I did most/all of the backend. I setup NestJS to run on an aws lambda.
All the files are stored in s3, and uploaded using presigned urls. I still need to stress test how large of a file I can upload but in theory is should allow uploads up to 5 gb.
NestJS was really good to get setup with, the start had everything we needed such as typescript and eslint. I like the opinionated structure of the framework, it allowed us to start working on the functionality without spending any time setting up the javascript project.
I was very curious to see how running a DI serverlessly would impact the quality of our project. We predicted that we would need to switch to another framework after a couple weeks because DI would be too slow. We expected DI to take a couple seconds just like Spring, but NestJS DI took about 80 ms with around 10 controllers and services. I think an equivalent app in Spring would take JVM startup time + ~2 seconds. I’m not sure if this is an impressive feat by NestJS or Spring is just very slow. NestJS did take around 850 ms to cold start, but 800 of those ms were from connecting to the mongo database.
The main downside of using NestJS was the learning curve. A lot of my team members were unfamiliar with angular style DI, and that caused me to be “The backend guy”. I think my team members were intimidated by the structure and boilerplate of the code. Everything worked out, but I ended up doing most or all of the backend.
I think if I were to do this project again, I would use fastify/Typescript, NextJS full stack, or a plain old lambda function. Unless the team is eager to learn a new framework, sticking with common basics would have allowed more of the team to contribute.
For infrastructure our #1 goal was to host everything for free. Ease of use was secondary. We chose aws because we had experience with it.
The structure of the app looked like this:
Route 53 -> CloudFront CDN -> API gateway -> Lambda Function
We kept the structure very simple, because we wanted to focus on building that app instead of working forever on the infrastructure.
You might have noticed that there is no static web hosting. We bundled the frontend into the backend as a static site and hosted it on the lambda function to keep the app simple. We didn’t want to spend a ton of time figuring out how to host a static site on s3, and NestJS has a built in static module that works really well. Plus, loading the static page would cold start the server so the backend didn’t need to cold start on the first request. A speedy response from the backend allowed the app to be more responsive. Bundling everything together improved the quality of our app, simplified development and simplified deployment.
We used the CloudFront CDN to reduce the load on the server from static files. So any non-api calls are cached on CloudFront. With this method we don’t need to worry about using lambda time for delivering common static files.
I really like the stack, it scales very well at the cost of vendor lock in. Our app was written so it can run standalone or on lambda, so migrating to another cloud is possible. The problem with migrating is that we would need to reconfigure everything and rewrite the file storage api.
The frontend was react + AntUI. I stayed away from this part of the code.