Building a Flutter application (for Web) with AWS Lambda Function URL backend using AWS CDK Pipelines (written in Java)

Wow, this is a long title 😉

In this post I am going to use CDK Pipelines to build a demo Flutter application hosted on AWS S3 with a Backend powered by AWS Lambda (using Function URLs).
The CDK code will be in Java, the Lambda functions in Typescript and the WebApp in Dart. Why? Because I love trying out things 🙂

The code used here is not production ready and does not fulfill required security best practices! 🙂

The CI/CD pipeline

The CI/CD pipeline for this project uses CDK Pipelines and that means it is build on top of AWS CodePipeline (which under the hood uses CodeBuild, CodeStar and other services to be functional).

It consists of different stages that build and deploy the corresponding part of the application:
– one stage for each lambda function
– one stage for the build and deployment of the Flutter application

The stages required by the CDK Pipeline to update itself are automatically added but not part of our code:

public CdkPipelineStack(final Construct parent, final String id, final String branch, final StackProps props) { super(parent, id, props); String connectionArn = "arn:aws:codestar-connections:eu-central-1:xxx:connection/xxx"; final CodePipeline pipeline = CodePipeline.Builder.create(this, getCodepipelineName(branch)) .pipelineName(getCodepipelineName(branch)).dockerEnabledForSynth(true) .synth(CodeBuildStep.Builder.create("SynthStep") .input(CodePipelineSource.connection("lock128/cdk-codepipeline-flutter", branch, ConnectionSourceOptions.builder().connectionArn(connectionArn).build())) .installCommands(List.of("npm install -g aws-cdk" // Commands to run before build )).commands(List.of("mvn test", "mvn package", // Language-specific build commands "npx cdk synth", // Synth command (always same) "bash start_codecov.sh")) .build()) .build(); pipeline.addStage(new CheckAgeLambdaStage(this, "DeployCheckAgeLambda"), getCheckAgeStageOpts()); pipeline.addStage(new PaperSizeStage(this, "DeployPaperSizeStage"), getPaperSizeStageOpts()); pipeline.addStage(new CalculatorStage(this, "DeployCalculatorStage"), getCalculatorStageOpts()); PolicyStatement flutterDeployPermission = getDeployPermissions(); CodeBuildStep buildAndDeployManual = CodeBuildStep.Builder.create("Execute Flutter Build and CodeCov") .commands(getFlutterBuildShellSteps()).rolePolicyStatements(Arrays.asList(flutterDeployPermission)) .build(); pipeline.addStage(new FlutterBuildStage(this, "FlutterBuildStage"), getFlutterStageOptions(buildAndDeployManual)); }
Code language: Java (java)

This is the definition of the CI/CD pipeline, it uses our Github repository as the source of the code and automatically starts after a push to the repository on the main branch.
The “Flutter Build Stage” is the one that currently builds the Flutter web application, deploys it and makes it available to the end user. Going forward, to make best use of Flutter, we would need to expand this stage to also be able to build an iOS application, an android application or an application for any other platform supported by Flutter. As a “goal” I would personally also want to extend this stage to be able to publish the apps to the corresponding stores (App Store, Play Store, Windows Store, …) – Thanks to my friends at cosee for the help and guidance around this process!

The architecture diagram of the application

What we are using to show-case the usage of AWS CodePipeline, Flutter as an application and AWS Lambda Function URLs as backend is not really an “application” – but it can do dynamic things and it can easily be extended to include a database backend, etc.

Infrastructure as Code using AWS CDK in Java

In this section you are going to have a look on the CDK code required to provision the infrastructure on AWS.
We are using AWS CDK written in Java – and because of that Maven as a build tool (Maven is the default tool for CDK projects – I’ve already used Gradle as build tool and that works in the same way.

The possibility of writing Infrastructure Code in Java is a great thing because it gives us the option to build on top of our existing skills – and I’ve written enough lines of Java in my career to feel comfortable using it to provision the infrastructure.
This is one of the best things in CDK: You can write your Infrastructure code in Java, Typescript, Python, … – and that helps us to build teams that only have “one” language as a “core skill” – one team might choose to develop in Java, anotherone in Typescript, another team could use Go – this allows the teams to build up mastery in a specific language!

In our example however, we are not making use of this possibility – I’ve choosen to rather go the opossite way: Combine a few languages, just to show that it works 😉

Stacks in the Example Project

The CDK code consists of four “stacks” – each of the Stack representing one “component” in this application.
In our example these four stacks are part of one CDK Application & one CodePipeline. In bigger projects, you might want to split these out into seperate applications – which introduces a lot tof things to consider (e.g. how do they fit and work together, etc.).

While writing this post, the four stacks combined are 129 lines of source code. With the help of the CDK Constructs that are being used this translates to over 1k lines of code in CloudFormation. We are only using L2 constructs here – there is way more constructs available that you can use in the Constructs Hub and also a lot of guidance regarding the usage of CDK over at CDKPatterns.

CDK Stack that provisions the infrastructure for the Flutter hosted website

Making a S3 bucket available to host our Flutter application becomes a very short piece of Java code as shown in the picture above.

Lambda functions behind Function URLs in Typescript and Python

This was definately one of the most awaited announcements in the Serverless space this year: The GA of the “Function URLs” for Lambda on AWS – and this is the reason for me using these as a backend in this showcase.
With this announcment, it is possible to directly expose your application running on AWS Lambda behind an HTTPs endpoint! Without an ApiGateway, Proxy, …
Provisioning the infrastructure for the lambda function with the function URL functionality activated is only a few lines in CDK:

CDK Stack for the Check Age Lambda function with the activation of the Function URL

These Lambda functions will now horizontally scale without us as a developer getting involved. More details on function URLs – there is a lot of good posts on it around like this one or this one.
Around scalability, fellow community builder Vlad has written up a great guide around scalability for containers on his website.

Web Single Page Application built using Flutter and the benefits of using Flutter

Flutter as a multi-platform, developer driven tool gives a lot of flexibility. With a single code base, you are able to publish your application to various targets. In this example, we are using the target platform “web” – which compiles the Dart code to a single page application.

This application is automatically aware of the size of your screen and is interative – which is another cool thing that Flutter takes away from you as a developer. A lot of organizations use Flutter today and the cookbook gives you an easy and good start into developing Flutter applications.

Our example application has three input fields that take input and pass it back to our Function URLs – and then automatically update a Text Widget with the results of the Function URL call. This implementation will work on all platforms.

What did you learn in this post?

You have learned how easy it is to provision AWS infrastructure using AWS CDK. You have also seen that you can easily combine different programming languages in a single CDK application and got an experience on how a CI/CD pipeline can help to automatically deploy our application using AWS CodeBuild.
In addition to that, you have looked at Flutter as a multi-platform development tool.

I’d be glad to get your inputs into my Github repository as a pull request or just as comments on the project itself.

Next steps

Further expansions needed to this project:
– use the CloudFormation Exports of the Lambda functions in the Flutter application instead of hardcoding the URLs for the Lambda Function URLs- enhance security for Lambda Function URLs
– add CloudFront in front of S3 to allow HTTPs connections to the Flutter App
– enhance CI/CD pipeline to package Android App using Flutter
– enhance CI/CD pipeline to package iOS App using Flutter
– enhance CI/CD pipeline to package Windows App using Flutter
Feel free to contribute and add your contributions to this project.

Listen to Werner Vogels talking about the benefits of CDK