Add a deploy SwiftPM plugin and a Swift-based DSL to the Swift runtime for AWS Lambda

Hello Swift Community,

I'm Esraa Eid, and I'll be working on the Add a deploy SwiftPM plugin and a Swift-based DSL to the Swift runtime for AWS Lambda project as part of GSoC 2024, with @sebsto as my mentor.

I want to initiate a discussion about the project idea and would love to hear your input and feedback. Please feel free to share your thoughts with me. Just a heads-up, this is my first post here and I'm still getting the hang of things. If I don't quite fit in or make any mistakes, please bear with me and pardon any mistakes! :nerd_face:

Overview:

Deploying AWS Lambda functions using AWS SAM (Serverless Application Model) currently requires manual creation of a deployment descriptor. This poses challenges for Swift developers, as it involves learning a new DSL and adopting new tools like SAM CLI and Docker. To simplify this process, the community proposed a Swift-based DSL and a Swift package plugin. However, these solutions rely heavily on accurately mimicking the evolving SAM AWS deployment descriptor.


Goal:

The goal of this project is to automatically generate the AWSLambdaDeploymentDescriptor library based on the SAM template definition. This generated code will be used by the Swift-based DSL to create SAM YAML templates required to deploy Lambda functions and their dependencies to AWS.


Deliverables:

  1. Automated Swift Data Structure Generator
  2. Enhanced DSL for SAM Template Definition
  3. Enhanced Coverage and Support for SAM Resources/Properties
  4. Integration with SwiftPM Plugin

Proposed Modifications:

  1. Automated Swift Data Structure Generator:
  • Conduct a detailed analysis of the SAM schema definition.
  • Develop a component capable of parsing the JSON SAM template definition and generating Swift Codable data structures.
  • Implement unit tests to ensure correct parsing of the JSON SAM template.
  1. Enhanced DSL for SAM Template Definition:
  • Modify the existing DSL to seamlessly integrate with the generated Swift data structures.
  • Develop integration tests to validate the DSL's functionality in generating SAM YAML templates accurately.
  1. Enhanced Coverage and Support for SAM Resources/Properties:
  • Extend the DSL syntax to include SAM template output sections.
  • Implement a mechanism to include generic CloudFormation text within the SAM template defined using the DSL.
  1. Integration with SwiftPM Plugin:
  • Integrate the automated Swift data structure generator and adjusted DSL into the existing SwiftPM plugin architecture.
  • Enable easy usage within Swift projects for Lambda function deployments.
  • Add unit tests to validate the complete workflow of using the SwiftPM plugin with the automated data structure generator and adapted DSL.

For additional details, feel free to explore the GSoC proposal on Google Docs.

Looking forward to your feedback and suggestions! :sparkles:

13 Likes

Great proposal! This will help lower the barrier to using Swift on Server even further.

Looking forward to seeing first results.

Wish you a great time working on this project. :grinning:

3 Likes

I’m thrilled to update you on my Google Summer of Code project! Over the past few weeks, with the support of my mentor @sebsto , I’ve been working on developing a Swift code generator to automatically create AWS SAM (Serverless Application Model) deployment descriptors. This tool aims to simplify deploying AWS Lambda functions by automating the generation of SAM YAML templates.

Key highlights: :pushpin:

  • Week 1-2: Focused on understanding AWS Lambda, SAM, and JSON Schema, and engaged with the Swift community.

  • Week 3-4: Developed a generic JSON Schema Reader and tackled SAM template challenges.
    You can review the code developed during these weeks in the following branches:
    β†’ branch #1
    β†’ branch #2

  • Week 5-7: Evaluated various Swift code generation techniques, including Swift Mustache, Swift Syntax, and Swift OpenAPI, eventually choosing SwiftSyntax.
    You can review the code developed during these weeks in the following branches:
    β†’ branch #1 Swift Hummingbird Mustache
    β†’ branch #2 Swift Syntax
    β†’ branch #3 Swift OpenAPI

  • Week 8-9: Defined a coding strategy for generating type definitions using Swift Syntax.
    You can review the code developed during these weeks in the following branches:
    β†’ branch #1
    β†’ branch #2
    Here’s an example snippet of the code:

    func generateStructDeclaration(for name: String, with properties: [String: JSONUnionType],
                                   isRequired: [String]?) -> StructDeclSyntax {
        let (memberDecls, codingKeys) = generateProperties(properties: properties, isRequired: isRequired)

        self.logger.info("Generating struct declaration for: \(name)")

        let codingKeysEnum = properties.isEmpty ? MemberBlockItemListSyntax {} : generateEnumDeclaration(with: codingKeys, isCodingKeys: true)

        return StructDeclSyntax(modifiers: DeclModifierListSyntax { [DeclModifierSyntax(name: .keyword(.public))] },
                                name: TokenSyntax(stringLiteral: name.toSwiftAWSClassCase().toSwiftClassCase()),
                                inheritanceClause: generateDefaultInheritance()) {
            MemberBlockItemListSyntax {
                if !(memberDecls.isEmpty) {
                    for memberDecl in memberDecls {
                        memberDecl
                    }
                }
                codingKeysEnum
            }
        }
    }
  • Week 10-11: Finalized the code generation, ensuring all data definitions were properly generated and compiled.
    You can review the code developed during these weeks in the following branch:
    β†’ branch #1
    Here’s an example snippet of the code:
    func generateDefinitionsDeclaration(from dictionary: [String: JSONUnionType]?) -> [StructDeclSyntax] {
        guard let dictionary = dictionary else { return [] }
        var structDecls: [StructDeclSyntax] = []

        for (name, value) in dictionary {
            self.logger.info("Processing key: \(name) in definitions declaration")

            if case .type(let jsonType) = value {
                self.logger.info("Processing type of value for key: \(name) in definitions declaration")

                if let objectSchema = value.jsonType().object(), let properties = objectSchema.properties {
                    let structDecl = generateStructDeclaration(for: name, with: properties, isRequired: jsonType.required)
                    structDecls.append(structDecl)
                    self.logger.info("Generating struct declaration for object schema with properties for key: \(name)")
                }
            }
        }
        return structDecls
    }

What's left to do? :pushpin:

The main task remaining is to generate helper functions for the generated SAMDeploymentDescriptor. This includes handling regex patterns with functions and trying to match the behavior of the SAMDeploymentDescriptor that was manually written. These helper functions will be essential for integrating the generated code into the DSL later on.

You can read the detailed progress and challenges faced in the full article here: Write a Swift Code Generator to Support the Creation of SAM Deployment Descriptors.

4 Likes

Very cool! Congratulations on a cool summer of code project and thank you for your work and sharing your experience in a writeup! :slight_smile:

Hope you enjoyed the experience and we'll see you around in the Swift community :slight_smile:

2 Likes