Building a simple RESTful API using Gradle, OpenAPI 3.0 and Java/Spring Boot
I have a Google Doc containing a bunch of recipes that I have gathered up over the years. Finally (Corona cooking!) it has got a little unwieldy, so a more convenient way to browse the recipes would be really nice. Of course, there are probably a tonne of really great apps for handling that, but it was the perfect excuse to get familiar with OpenAPI 3.0…
Long story short, check out this Github repo, where I pushed the code (so far). It has an OpenAPI 3.0 specification of the recipes API that allows listing all recipes, creating a recipe and listing a specific recipe. It can link to an image of the recipe hosted in an S3 bucket. The server stubs are autogenerated using Gradle and OpenAPI. The implementation is Spring Boot 2, with a DynamoDB persistence layer to store and retrieve the recipes. The Spring Boot application is hosted either locally, or on AWS Lamdba. API Gateway is used to proxy requests to the Spring Boot application. It will shortly have Terraform scripts for deploying everything on AWS, and I may add an OIDC authentication layer to hide super-secret recipes!
In a previous role I had already experienced two really huge plus points of using a specification like OpenAPI. The first is the SwaggerUI as a documentation for the API, that can be used by people who want to consume the UI. Those people may not always be hardcore developers who are familiar with the intricacies of GET, POST and HTTP response codes, but they just want to use parts of the API in a Python/R script, or one of many graphical tools that support REST APIs. The second key use was as a lingua franca for a front-end and back-end team to jointly discuss requirements, and finally agree on a contract to code against. It needs a bit more talking up front, but can be super efficient in the implementation phase. But I hadn’t yet had the opportunity to use the code generation capabilities of OpenAPI. In case you’re not familiar, one of the things that you can do with OpenAPI, is to write the specification for your API as yaml, and then use that to generate client and server stubs for the API in a variety of languages.
I also want to host the API on my AWS account, as a sub-section of my website. I don’t want it to cost very much, and I don’t want to have to keep things patched. So serverless has a very strong pull here… Therefore I need a solution that I can deploy using AWS Lambda. Also in the mix is API Gateway, and S3. I’ll be using Java, which isn’t necessarily the go-to language for microservices, but hey, sometimes you have a large legacy code base, or maybe you’re just most familiar with it.
There were a bunch of really helpful websites that I used for reference:
- AWS Spring Boot - Quick start
- AWS - Lambda Proxy Integrations
- AWS - resize images on the fly with S3, Lambda and API Gateway
- Lambda and API Gateway with Terraform
- Java and Lambda Cold Start
- When I got stuck thinking about S3 and image download
- and to give me a warm fuzzy feeling when I decided what to do
- Nice discussion of redirect, vs. pre-signed URL, vs. pass through
- Just interesting if you’re designing a RESTful API
Anyway, there are a few relatively new Java frameworks for writing microservices in Java, and there is Spring Boot. Which isn’t really designed with it in mind, but does support it and has the added benefit of being able to be deployed ‘old-school’ on a Tomcat application server. The two other frameworks that I had in mind are Quarkus, and Micronaut. When I was doing my reading I found a nice review/benchmark of the above three options. Perhaps the take-home is maybe in many cases it doesn’t really matter, most important is what you are comfortable with. If you really care about more detailed benchmarking check here. I hope to find the time to port my app to one of Quarkus or Micronaut at some point in the future. That would be an interesting test.
In general I’m pretty happy with the outcome. It works! It didn’t take too long to tie it all together. It’s obviously a toy project, but it let me learn a little about Spring Boot, especially HTTP 301 response status code and 418. Cold start times for the Lambda are still pretty bad, for me at the moment something like 10 seconds on a 1Gb RAM lambda. That’s almost certainly possible to improve a little, and I may add some notes here if I find a few useful things. In any case for me it isn’t a big deal, and if you’re running frequently it also shouldn’t be a huge deal. However, you will certainly want to do your due diligence on that. I also failed to learn something about OpenAPI 3.0 and the slight annoyance that it doesn’t seem to be easy to serialize the auto-generated classes to persist in DynamoDB using the AWS Java SDK 2.0. I must have missed something obvious here. Let me know! I will follow up with a few more blog posts on a couple of the specifics that came up. Expect to see something on:
- Auto-generation of Spring Boot server code using OpenAPI 3.0 and Gradle (and how to deploy SwaggerUI).
- How to convert an existing ‘normal’ Spring Boot application to use AWS Lambda and API Gateway.
- Persisting with DynamoDB, and different methods to access images from S3 (using Spring Boot).
- Deploying the whole lot using Terraform.
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License .