This topic has been discussed previously but I have only found specific solutions and I’m lacking a bit of consensus or tips from the serverless pros.
The background: I am in charge of the development of a new solution, and I wish to migrate the team culture to serverless and more recent technologies such as GraphQL. The background of my team is nodejs/express REST APis, so for this project I will just introduce the serverless component to them.
I would like to get rid of express, as I feel that specifying the routing directly from the serverless conf makes more sense. The problem is that I see a lot of boilerplate and lack of DRY code when doing so, and thats when I start to think that I-m doing something wrong.
I see different approaches around, but I’m not sure about the pros and cons:
Specify all functions into serverless.yml (one per resource and method). This means to repeat a lot of code both in the handler and the configuration.
Single handler per resource, route the methods/parameters in the code as suggested in (Use wildcard in path for http endpoints). This makes more sense, and boilerplate is only added per resource.
Use a single endpoint/handler for everything and route in the handler. This would resort to using express or other custom solution, I feel that this does not make sense for new projects.
My natural choice would be 2) as the least painfull, but I’m still not sure about other options and particularities of doing things this way. As I said before it would be nice to know the opinion of more experienced developers.
PS: Anyhow, the team would be pleased when I introduce Graphql for the next project (that is almost painless for me)
After a long night and sleepy morning I have tested the previous approaches and I have slightly changed my point of view…
Option 1 is still not viable, even at the maximum level of encapsulation I feel that there is still too many boilerplate code. A moderate sized REST API has too many endpoints to be directly specified in the serverless.yml file, perhaps it is fine for small sized APIs…
Option 2 was my favourite, but after some test I see some flaws… Mainly regarding routing, the solution proposed in the cited post is not scalable. As a heavy user of express I think that “manually” managing the routing of methods, params… again, in a large API you are introducing lot of not standard code… again not safe.
Option 3 seemed almost discarded for me, but is now my way to go. If I have to introduce my team to serverless I will do so by using serverless as a proxy and as a way to deploy my API (https://serverless.com/blog/serverless-express-rest-api/)
I am a strong believer of GraphQL and serverless, their many synergies make me feel it is the way to go. However it still too early for me and my team to migrate to such a new stack.
Am I biasing my decision towards using technologies which are more confortable for me?, is there any gotcha in using express that I am missing here?
Hey @jacintoArias, I don’t think there’s a right answer here, but I think you’ve nailed the key aspects. I don’t think there’s anything wrong with starting with an Express proxy – it’s a comfortable switch while still showing the benefits of Serverless. Down the road, you may wish to write resource-specific handlers without the use of a web framework, but it’s not required now.
For a counterpoint on using a web framework, you should read Ben Kehoe’s thoughts on using the lambda-proxy integration. It’s a good explanation of why you might eventually move away from this approach while still noting that it’s a great on-ramp to Serverless.
that post develops on the pitfalls I was afraid of. I will tweak my production applications by using a hybrid approach (as described in the mentioned blog post) in which you use a lambda proxy to an express app but declaring the endpoints on the serverless.yml file (you avoid the boilerplate code and gain visibility, security and the self documenting aspect of API gateway).
As I mentioned I will move away from this approach, but from my point of view I won’t be moving away from lambda proxy serverless, I will be moving away from REST and serverless will help me do that.
Alex is 100% correct about their being no correct solution.
Where possible I would stay away from 3. It will lead you down the path of building monolithic applications with a single Lambda that does everything. Once you start using GraphQL you may find yourself going down this path too if you’re not careful.
You can reduce the amount of boiler plate in option 1 by extracting common code into shared libraries but I’ve always found the though of one Lambda per API endpoint to very painful.
My preference for REST API has typically been one Lambda per resource. The only routing is based on the verb and resource ID.
I just wanted to update this for anyone that follows this conversation with the same problems.
You are absolutely right, and experience has led me to that exact path. Express has been a powerful entry point for us, but we are removing it in favor of doing the routing with serverless. We now even have multiple services sharing resources so modularity is key.
We have services that are specific for creating resources, and several APIs services which are modelled as a set of Lambdas (one accessing each resource as you suggest). Shared libraries are a must for reducing boilerplate code and improve reusability for example when accessing and modelling the data layer.
However this approach is very new and there aren´t many examples and/or good practices out there, just tiny bits of advice… I could really use an opinionated example on how people are organising big projects…
I´m currently struggling with my CI/CD pipeline, I could really use a monorepo for all my services
I’m finding myself in the same situation as outlined in this thread. I imagine anyone that’s interested in developing a larger and/or growing REST API will wrestle with the same questions of how to structure their project and Lambdas etc. How you decided to structure your shared libraries (e.g. for data access etc.) would be very helpful for me to know. How did you decide to break up your serverless.yml files? Is there a separate one for each resource and then the functions defined inside are only relevant to that endpoint (w/ GET/POST/etc)? If so, then how do the different services share common code? Is everything in one GIT repo?