Loading summary
A
Hello and welcome to aws bytes episode 139. I'm Owen and I'm joined again by Luciano. Building a new API on AWS presents you with a lot of options. There's tons of frameworks out there for any language you can imagine, but what happens when you decide to implement some or all of that API with AWS Lambda? It can bring some benefits, but there are a few head scratching considerations. Not all API frameworks are designed with AWS Lambda in mind. There is one actually, that is and today we're going to revisit power tools for AWS Lambda and dive into the amazing REST API support it offers, specifically covering the Python version of the library. We've been using this framework a lot and really want to share how it makes API development much faster while still giving you all the features you want like routing, validation, open API support, middleware and more. So let's get started. AWS Bytes is brought to you by Fourtheorem. If you want fast modern APIs with great developer experience, Fourtheorem is your partner. We'll collaborate with you to ensure you have great performance, security, scalability and most importantly, satisfied API users. Reach out on LinkedIn, BlueSky or through4Ethereum.com all of our details are in the description. You don't always have to use lambda for APIs, of course, there's lots of options out there. Before we get into the Lambda story, if you're running on a server or container, what frameworks would you consider?
B
Yes, so I am a big fan of Node js, as many people are probably aware. So in Node js, the most famous web framework is probably Express has been around since almost forever since Node JS existed. Although I have to say in the recent years since Fastify came out, I think it's a slightly modern take on Express and much more performant I think has a nicer developer experience. So these days if I have to pick a more traditional web framework for Node js, probably Fastify will be my first choice. And I've been intrigued by a new framework came out I think last year and it's called Hono, you might have heard of it because it's quite interesting in a way that it's very minimal, but at the same time it's built with distribution in mind, I could say, because they made it work with effectively every major JavaScript runtime. So it works in Node, it works in Ban, it works in Deno, and also it can work in multiple environments when it comes to picking for instance a serverless. So to Speak environment. Like it can work well in Lambda, it works well in Cloudflare workers and I heard people trying it in all sorts of environments and everyone says just works out of the box. So could be an option, you can run it in Lambda if that's your thing. But of course we'll talk about the differences between running a more traditional web framework in Lambda and using something like Power tools. If we have to pick other languages, people might be aware that I also like Rust and in Rust there is still a little bit early I would say, because Rust is such a newer language and the ecosystem isn't as developed as Node JS or Python.
A
But.
B
But there are quite a few web frameworks that are quite good and one that I've been using and I like is called Axum. And you can also use that one in Lambda effectively by embedding the entire web framework into the monolithic Lambda approach, basically. And then when it comes to Byton, the most famous ones are probably Flask and Django. But again there is a more modern take which is called fastapi, again the name Fastify fastapi, maybe there is some curious overlap there. And yeah, fastapi is really good. I've been using it in the past and it's really nice to use. So yeah, the idea again is that you can take any of this framework we just mentioned and package everything in a Lambda lit and that's something that people sometimes do. I don't necessarily like this approach, I generally prefer to have fine grained lambdas. But yeah, I guess you need to figure out exactly what are you trying to optimize for. Like if you already have a web server and it's relatively small, you just want to move it to Lambda because of scalability, because it scales to zero, then you can do it and it should work reasonably well. What do you think, Owen?
A
Yeah, I'd agree with all of that. I haven't got to try Hano yet, but it seems really, really good. But I do like, you know, something that it depends on what kind of project you're building, but something that gets you going really quickly. And you know, Python is generally a fast language to develop with. Very productive, everybody can get involved. And I really like the fast API approach as well. And the approach we're talking about today with Lambda is actually modeled on fastapi, so it's very similar. And this is all about Python power tools and we did mention power tools in the past, AWS Lambda power tools mostly in the context of metrics and logging and tracing because those were the three pillars that kicked off the whole Power Tools adventure. I think the first language was supported by. The first language supported by Power Tools was Python back when Ator Lesa kicked off the project. I know there's a whole team behind it now, and the amount of development that has been done on it for an AWS open source project is pretty astounding. And the quality and level of documentation is one of the best I've seen for any open source project. The Python one is by far the most fully featured version of Power Tools because it was the first. In addition to the metrics logging and tracing, it supports middleware a bit like MIDI does with node JS functions. And then you've got all sorts of other features like types for lambda events, parameter retrieval, feature flags, streaming responses, item potency support, and then you have validation and parsing. And there's a whole web framework essentially built into Power Tools for building REST APIs. So validation, parsing, REST APIs, support kind of work together to give you this really nice API framework with a good developer experience. Should we talk actually, what does an API framework need to have? What would you like to see from it?
B
Yeah, exactly. I think there are some components that every web framework needs to have to give you effectively the basic tools to build an API. And the first one is of course, routing. Like you need to be able to understand what kind of HTTP request is coming in, what's the method, the path. Maybe you have some path parameters. The routing layer should be able to effectively address specific parts of your code and respond to specific requests and ideally do all the parsing of path parameters and give you nice ways to access all this information. And with that also comes error handling, like what happens if a route doesn't exist? The framework should take care of doing common responses like a 404 for you. Other concerns could be serialization and deserialization. You will have requests coming in, you'll need to be able to process these requests. So most of the time it's probably going to be JSON. But JSON is not the only format. You might have like a form that is being submitted and you want to handle it as part of your API. You might have uploads of files, so there can be different kinds of encodings effectively that your API needs to support. A good framework should be able to to give you the tools to process all the different kinds of data and turn them into something that you can actually programmatically use. And similar with responses, you might need to serialize an object into a specific response. Serializing, probably JSON again, but that's not necessarily the only option you might want to support. So again, the framework should give you all the tools for serialization and deserialization. Validation is a very related topic because when you are accepting data, it's always a good practice to do validation. So hopefully that needs to be part of the tools that the framework give you. And one thing that I really like a lot to see in frameworks, and this is actually something that is not always present, generally you need to rely on some kind of third party plugin that's the open API specification. So I think I like when a framework allows you to use types and strongly typed code in general in your code and then it's able to build an open API specification starting from your routing definition and from the types that you used in your endpoints. And I guess if you put all of that together, you can get to a point where you have nice types, auto completion and type safety for all the requests and responses. I think that will be kind of the golden standard for me. When a framework gives you all of that, I think you end up with a very nice developer experience and you can effectively develop your API with the confidence that you are managing the data properly. You're not going to have surprises where maybe you're trying to access a field that doesn't exist, or maybe you're going to return a response that doesn't necessarily match what you promised the user you would retire. So I think that's kind of my ideal framework. How does Power Tool help in this sense? Does it match this definition or is it very far away?
A
Yeah, I think it hits everything you've mentioned. Let's go into it in a bit of detail. So when you have lambda behind an API, you're generally talking about API, Gateway, REST API or HTTP API. But it could also be an application load balancer, a function URL, or even a VPC lattice. And Power Tools supports all of those things. So there's a great page in the Power Tools documentation all about rest APIs which we can link in the show notes. It's very comprehensive. The REST API support essentially first provides a set of resolvers, and there's a resolver for API, Gateway, HTTP API, Application Load Balancer, etc. And they all work in a similar way. So you basically create one of these resolvers and when you do that, you're creating a router router that can be used to route a lambda HTTP event to a set of functions that you define for your routes. And once you have this resolver, the lambda handler function becomes very small. It's actually one line generally. So you have your typical lambda handler with event in context, and you just forward that on to your resolver's resolve method and then you can just create specific functions for each route. Let's say you have an API to do crud operations on a to do list items, you have your create todo function, and then you'll decorate it with p post with the path parameter todos. And there's lots of other options you can put into that decorator when it comes to providing additional details that you might want in your open API specifications. And that's it really. That's how you get up and running. That's how you create your first set of APIs. And power tools is just doing a lot of the work for you. You don't have to worry about parsing JSON or looking at the event yourself. A lot of the rest of it is just managed.
B
Yeah, I think I want to spend a little bit more talking about validation and type checking and all the options you can generally have there, and then see exactly how Power Tools helps there in the case of Python. But yes, we just say that validation is effectively one of the main things that an API should do first. Like whenever you receive a request, you need to validate, and that's probably going to be one of the first lines of code that you would write in your own handler. Right. If you had to write all of that manually. And this is a good practice for a few reasons. One is definitely a security best practice because of course, if you're going to validate the incoming data, then you have a little bit more certainty that you understand the shape of the data coming in, and that reduces the risk of all kinds of injections. Also, it reduces the risk of you ending up creating maybe inconsistent data in a backend system and maybe, I don't know, storing it in a database record or something, which will eventually lead to subtle bugs here and there because you have all these different objects stored with slightly different, I don't know, shape. So that's definitely one of the benefits of validation. Then the other thing is that if you have a very strict definition of what your input should look like, then you could also create strongly typed interfaces to represent that input, which in the language of choice, let's say Python in this case, that will give you nice auto completion and type checking. So once you are at that point in your code, when you are using a specific type, and you have validated that the input matches the type, then everything else should get so much nicer because you can easily see all the fields available, autocomplete all the types and so on. So when you combine the two effectively, that reduces the risk of bugs because you're checking that the data makes sense. And then at that point you have a strongly typed interface. And that's generally a problem that exists with languages that are dynamic like Python and JavaScript, where if you don't have that diligence of doing all this, defining the interfaces and doing a proper validation, that's generally a very common source of bugs. So that's why I think I wanted to stress a little bit more how important is this point. And then when it comes to Power Tools, they put a lot of effort into trying to give you good tools to do all of these things in a nice way and without having to write a lot of code yourself. And empower tools, they specifically leverage a library called Pedantic. And I think it's important to explain a little bit more how pedantic works and what is the difference between validations and parsing. And that's another thing that if you just look at the list of features that Power Tools has, you can see that there is a section for validation and there is a section for parsing. So it might be a little bit confusing to people, like what is the difference between the two and the way I will describe it? And maybe this is not necessarily a canonical definition. Is, is that validation? You effectively are just verifying that the data you are receiving matches a specific set of rules that you are defining. And the result of that validation can be either true, like everything matches so the data is good, or if it doesn't match, you might get like a list of errors that try to describe you. I don't know which field didn't match specific rules. And you can use that maybe to provide a response to the caller. Parsing is a little bit more than that. It kind of solves the same problem in a way, but. But the approach is a little bit different. So with parsing, you are generally starting from a strongly typed model, and then you are effectively trying to read the input data and start to populate this model. And then if everything goes well. So if you are effectively able to populate the model entirely, respecting the types and the constraints that you define in that model, you can also say that the incoming data is valid, but the output of that operation is that it's not just a boolean that tells you true, but you now have this object that you can use and is strongly typed and you can use it in a much more structured way as opposed to just a boolean. And then you still need to read the raw data. And libraries like Pydantic will give you lots of tools to do. Also more advanced things like coercion, more advanced validation rules. So you are effectively, you can also normalize the data as you're doing all this validation and parsing. So in a way we could say that parsing is a more powerful way of doing validation and it gives you a lot more like coercion, autocompletion, type checking. So generally is what I would prefer these days. I wouldn't do just validation anymore because I think it only solves a portion of the problem. Parsing is much better. So how does Power Tools help there? Can you give us a little bit?
A
I think you've covered it pretty well. I mean, if you've used FastAPI or even similar JavaScript type frameworks using Zod, then you'll be familiar with the idea. So and if you like to write typings in your Python code, then it'll definitely be very easy for you because you just define your types as pedantic models. That's just like creating a data class in Python. But you get all of the additional descriptive nature of pedantic models and custom validation if you want. But it can be very simple. You just define your request and response types as pedantic models and then your type declarations for the functions that manager routes use those types. You can also do type annotations for things like query parameters, so you can strongly validate those too and get auto completion with them. And even headers as well can have types. Of course, that gives you, as you mentioned, autocomplete in your ide. You get the validation and the parsing all for free. You don't have to do any serialization or deserialization from JSON or whatever you're using. And that's not just for APIs. Actually these parser features can be used with any event type. So when we're working with EventBridge events, we also often define pedantic models for the EventBridge events and use those parsers there too. And one of the huge benefits then is when it comes to OpenAPI specifications, these same models are used for generating all of the JSON schema and all of the documentation for your Open API or Swagger docs. And Power Tools has great support for that. It can even provide a route like OpenAPI which will serve the JSON or HTML documentation for the OpenAPI spec. And it's all generated from the pedantic models, so it becomes very easy to iterate on it. We also generally when we're doing projects like this, we'll generate the open API spec at build time, like in the build pipeline or in a pre commit hook even. And then if you've got front end code or client SDKs that you want generated, you can just take that immediately and generate or update your client SDKs and then you have type safe JavaScript or whatever other language you need. So if you're doing a web application, you've already got a library that has very strongly typed, very developer friendly bindings for the API.
B
Yeah. So I guess the next question is, do you need to use the Lambda Lith approach to leverage all these nice features that Power tools for Python gives you?
A
Yeah, that's a good question. And maybe we should define exactly what we mean by lambdalith because it's a bit of a contentious topic I think in the world of AWS lambda right now. Typically, I think when Lambda first came out and many years, one of the benefits that was spoken about was the fact that you got very specific single purpose functions with very fine grained permissions and very specific dependencies that were lightweight. And then you could tune your memory and CPU and everything very specifically to each individual function. And then the approach with API Gateway was you would have one route in your API which went to one lambda function which had the resources and only the resources and only the permissions it needed. Now people can find that a lot to maintain, although it doesn't have to be. But the other approach is forget all that, let's just bundle it all into one function and have all our API routes be backed by one function. Now that can be. I can see the appeal for sure because it simplifies your deployment. It means that if you've got warm containers that served one route, they can also be used warm to serve other routes. You do lose some benefits because you have to have a broader set of permissions and sometimes you might need a larger set of dependencies to bundle into your function. So there are pros and cons to both approaches. We don't necessarily have to go into what's good and bad. Now the Power Tools documentation does more or less advocate for lambdalith functions and it even says things like the OpenAPI specification only really works if you're using a Lambda Lith. So everything all routes in one function, but that's not necessarily true. We were able to work around that. So you can basically set up your API resolver with power tools and then you just decide which functions to attach it to. So the way we do it is we have basically a separate module outside of all of your lambda handlers where your resolver is created, and then you can just import that into the lambda handlers that you want to be part of that resolver and share the same routing mechanism. And then when it comes to generating the OpenAPI spec, for example. So one of the issues is that if you've got single purpose functions, each function had its own resolvers, so they weren't aware of the whole API, so they couldn't generate a full spec. But if you have a common resolver declared and you just import that in each event handler, you can just have a script locally that will basically load all of your handlers. They'll all share the same resolver just at local time or at build time. Then you generate the open API spec in a script and then when you deploy it, you can decide whether to package each handler into separate functions or all into one function. And then. So we've done multiple projects where we do this and you. Basically we've done it where you do the lambda lith approach, which actually can work very well at the start of a project if you want to iterate really quickly because you only had one function to worry about. But we've also done it with single purpose functions and you just have this shared resolver and then you have multiple deployments and then you have the whole build pipeline which is generating the open API documentation and the client bindings, and it works with both approaches, so it doesn't have to be a lambda lift.
B
Yeah. I think if people are curious about our rationale when it comes to lambda leads, we have a dedicated episode, I think it's 92, where we talk about some approaches on how you can decompose an existing lambda into multiple functions, and we also talk about the benefits of doing that. Now, again, I don't want to necessarily advocate for single purpose lambda functions, although it's generally my preference. But yeah, I know that there are some good use cases also for lambdavids, but that will be a little bit out of topic. So we'll leave you to the other episode in the show notes, if you're curious. I guess the other question I would have, and you have a little bit more experience than me with power tools for Python, what's the local development experience?
A
There's nothing specifically In Power Tools that gives you a local development experience out of the box. But it actually becomes really easy once you have this API resolver set up. It's just really well archetyped and you know, it becomes a very thin layer on top of your business logic, the API layer. It becomes really concise and very portable. So the way we would just do it normally is you have your handlers and these routes and then all of your logic like your services and your repository patterns and everything sit separately. So you could actually easily migrate your whole API to a completely different framework if you wanted to. But when it comes to local development, obviously if it's fast API, you can just run it locally. You can do something very similar locally with Power Tools. And when we are doing this approach, we generally just set up local server script, which is like a simple Python flask server, which has one route in it and matches every request, just as a very simple translation of the flask request into a lambda event, HTTP API or ALB event, and then invokes the lambda handler's code directly. And then the Power Tools API resolver will take the request from there, just as it does in a real lambda environment. And it's just generally a few lines of code to that. And then you've got a local simulation server that behaves like API gateway in Lambda and it can really speed up development because you don't have to deploy every time. I know even that some people are using lambda power tools in containers, like with Fargate, because it has so many nice tools there. You can actually take a similar approach and you can just run a server like that very lightweight proxy and forward onto AWS Lambda for Power Tools, make use of the resolver and then you get all the other nice features like tracing metrics, logging, item potency, whatever. So it doesn't have to be with an amulet to get benefit for all this. Great work.
B
Yeah, that's pretty cool. I guess. Before we wrap up, maybe worth mentioning, what's the status of similar features with the other versions of Power Tools? So the other languages, and you might be aware that Power Tools is not just a Python project, exists for TypeScript. Net and Java. Unfortunately Python is always like the main line, like it's probably the first one where they introduce new features. And this API framework development has been one of the latest additions. So unfortunately all the other languages still have to catch up with this feature. So there is some support. For instance, in the TypeScript one you have Zod available if you want to do parsing, but then you don't really have a nice cohesive ecosystem of features that gives you an entire API development type of approach as you will get with the Python version. But hopefully that will change soon. So keep an eye on the various versions. Maybe there could be an opportunity to contribute as well. Always remember that Power Tools is an open source project, so everyone is able to contribute if they want to. And of course you can always build your own abstraction as well. Like if you're familiar with other frameworks in the language of choice, you can probably bring some components of this framework and use that as a way to create your own mini API framework on top of our tools.
A
Yeah, for sure.
B
Yeah.
A
I mean, I think when it comes to the more mature languages that have been doing web development for 20 plus years, like the Java and Python runtimes. Sorry, the Java and. NET runtimes, there's so many libraries out there for doing routing and you know, frameworks that have a long history, like with. Net, you can integrate asp. NET for that, I think even the CDK patterns, if I remember correctly, or maybe it's in the. NET templates, they'll give you patterns for doing that out of the box. So perhaps there's just not as much of a need as there is in Python, I guess. In conclusion then, if you are a Python developer keen on Lambda, looking for a framework that is a bit like fastapi or one of the other ones that you may have used, this is a great option, we feel at least. But let us know what you think and if you've got any nice alternatives or pro tips for Lambda backed APIs. Thanks very much for listening and watching and we'll see you in the next episode.
Date: February 19, 2025
Hosts: Eoin Shanaghy & Luciano Mammino
Theme: Exploring how AWS Lambda Powertools, particularly the Python version, enables efficient, fast, and feature-rich API development on AWS.
This episode delves into the challenges and solutions for building modern APIs on AWS Lambda, with a special focus on AWS Lambda Powertools for Python. Eoin and Luciano walk through common web frameworks for various languages, identify what makes a great API framework, and offer a detailed examination of Powertools’ REST API features—discussing routing, validation, OpenAPI support, development workflow, and more. The conversation also compares single-purpose Lambda functions versus the "lambdalith" approach and touches on the state of API support in Powertools for other languages.
Key Requirements:
“When a framework gives you all of that, you end up with a very nice developer experience and you can develop your API with the confidence that you are managing the data properly.”
— Luciano (07:54)
Supported Integrations:
Routing Made Simple:
@post("/todos")), supporting advanced OpenAPI attributes.Automatic Handling:
"One of the huge benefits then is when it comes to OpenAPI...PowerTools has great support for that."
— Eoin (15:37)
“We’ve done it where you do the lambdalith approach...but we’ve also done it with single-purpose functions and you just have this shared resolver...works with both approaches, so it doesn’t have to be a lambdalith.”
— Eoin (18:54)
For more on this topic, check Episode 92 about decomposing lambdaliths.
“Hopefully that will change soon...PowerTools is an open source project, so everyone is able to contribute if they want to.”
— Luciano (22:45)
Python-centric AWS Lambda developers searching for a featureful, productive framework—especially those familiar with FastAPI—will find AWS Powertools’ REST API module an excellent fit. Offering strong routing, validation with Pydantic, automatic OpenAPI generation, and robust developer ergonomics, it bridges best-in-class API practices with serverless simplicity. Although other language versions are catching up, Python Powertools currently delivers the richest experience for API builders.
Listeners are encouraged to share their approaches or alternatives and check episode 92 for deeper dives on the “lambdalith” topic.
[For further reading/listening, see the episode notes for links and reference materials.]