230 Commits

Author SHA1 Message Date
Sébastien Stormacq d18360e636 fix: Add support for DISABLED status in SES verdict enums (#110) (#111)
## Motivation:
AWS SES can return "`DISABLED`" as a valid status value for spam, virus,
DKIM, and SPF verdicts when certain checks are disabled in the SES
configuration. However, the `SESEvent.Receipt.Verdict.Status` enum was
missing this case, causing JSON decoding to fail with a `DecodingError`
when parsing SES events containing `{"status":"DISABLED"}`.

This issue was reported in #110, where users encountered parsing
failures when processing legitimate SES events from AWS that included
disabled verdict checks.

## Modifications:
Added `.disabled = "DISABLED"` case to the
`SESEvent.Receipt.Verdict.Status` enum in
SES.swift
Converted the existing test to a parameterized test using Swift
Testing's `@Test(arguments:)` syntax
Added a new test case (`eventBodyDisabled`) that includes a SES event
with `spamVerdict.status` set to "`DISABLED`"
Updated the test assertion to verify both `.pass` and `.disabled` status
values are handled correctly

## Result:
SES events with verdict statuses set to "`DISABLED`" will now decode
successfully without throwing errors. The library correctly handles all
valid AWS SES verdict status values: `PASS`, `FAIL`, `GRAY`,
`PROCESSING_FAILED`, and `DISABLED`. The parameterized test ensures both
standard and disabled verdict scenarios are validated automatically.
1.5.0
2026-01-29 07:36:21 +00:00
Sébastien Stormacq 02b0e3455e Modernize CI and use Swiftlang's GitHub actions instead of Swift NIO's (#109)
Modernize CI and use Swiftlang's GitHub actions instead of Swift NIO's
1.4.0
2025-11-30 22:47:30 -08:00
Sébastien Stormacq d47a3bf631 Add Decodable Request to APIGatewayRequest (#108)
Add Decodable Request to APIGatewayRequest
2025-11-30 22:42:51 -08:00
Matt Massicotte f5c173c557 Decode query params for WebSocket APIs (#107)
APIGatewayWebSocketRequest was not decoding url query parameters from
event payloads.

### Motivation:

API Gateway WebSocket endpoints do support capturing and forwarding
query parameters. Probably just omitted because it isn't particularly
common.

### Modifications:

Added the field. Added a test. Verified against a real system that uses
the feature.

### Result:

Query parameters for APIGatewayWebSocketRequest will be available to
clients.
1.3.0
2025-11-11 13:11:23 +01:00
Sébastien Stormacq a7f7cf4c99 More tests on dates with fractional seconds (#106)
Based on the discussion here
https://github.com/swiftlang/swift-foundation/issues/1561#issuecomment-3448853449
, I added a few more tests around dates with fractional seconds
2025-10-27 13:40:29 +01:00
Sébastien Stormacq 213b75d640 Fix #100 (#105)
Use `swift-http-types` version 1.5.1 or more recent
1.2.4
2025-10-26 19:37:14 +01:00
Sébastien Stormacq 5ec2627e88 Attempt to fix issue #102 (#104)
After the explanation received by Stephen
(https://github.com/swiftlang/swift-foundation/issues/1561#issuecomment-3448697120),
change the test to make it pass with Double+Double date precision
2025-10-26 19:27:29 +01:00
Ben Rosen a85c7a7846 Fixes and tests for decoding binary items and empty lists in DynamoDBEvent.Decoder (#103)
Cleaned up version of
[#61](https://github.com/awslabs/swift-aws-lambda-events/pull/61) that
also has tests.

This PR makes it so that in lists, the decoder will not try to access
the 0th index of an empty array.

This PR will also make it so that `AttributeValue`s of type `.binary`
will properly decode to base64 Strings when String is put as the type in
the the `Decodable`. To avoid including `Data` in the code, I included
code from the original source of the base 64 decoding methods
(https://github.com/fabianfett/swift-base64-kit) to add in the
corresponding encoding methods. However, I saw lots of Foundation is
imported throughout so I reverted it. What are your thoughts on this
matter?

I also added tests that aim to make these failure points more resilient
in the future.
1.2.3
2025-10-22 21:29:40 +02:00
Sébastien Stormacq f6fc221450 Update License header according to /awslabs standards (#101)
Update legal files and license header in source files to the AWS
standard
2025-10-21 23:12:17 +02:00
Sébastien Stormacq 40db1cc31c Use HTTP Types v1.4.0 (#99)
HTTP Types introduced a breaking changes in v1.5.0
https://github.com/apple/swift-http-types/issues/107

This PR pin the dependency to v1.4.0
1.2.2
2025-10-20 21:42:14 +02:00
Sébastien Stormacq cd4290a0df Add retroactive where appropriate (#98)
Removes compiler warning when we add dependency on Codable.
2025-10-20 20:34:54 +02:00
Sébastien Stormacq 3a9de7cb34 change refs from /swift-server to /awslabs (#97) 2025-10-17 17:57:29 +02:00
Sébastien Stormacq 850df86525 [ci] Apply recommendations for security and reliability #24 (#96)
Apply recommendations in code and documentation

- [CI] restrict permissions to read-all instead of the default write-all
2025-09-27 12:12:18 +02:00
Sébastien Stormacq 7a33d6cf01 [ci] Remove the docker-based CI files (#95)
Before we started using GH Actions, the CI was based on docker compose
files.
This PR removes these Dockerfile and Docker compose definitions.
2025-09-26 10:10:51 +02:00
Sébastien Stormacq cac8d84946 Update getting started links in readme (#94)
Updated links in the readme to point to the latest tutorial and guide.
2025-09-07 10:46:30 +02:00
Natan Rolnik 5aa3a63058 Mark deprecated FunctionURLResponse init as @_disfavoredOverload (#93)
In a previous PR (#91), a new init with a different parameters order was
added, marking the previous one was deprecated. The problem is that the
compiler doesn't know which one to choose when omitting the final
parameters.

This PR fixes it by marking the deprecated init with
`@_disfavoredOverload`.
1.2.1
2025-08-07 07:06:09 +02:00
Natan Rolnik 89f1172a7e Add Codable helpers for FunctionURL, APIGatewayV2, and SQS (#90)
Add helpers for FunctionURL, APIGatewayV2, and SQS events to ease usage
of `Decodable` and `Encodable` types

### Motivation:

When using Function URL (or API Gateway) events and outputs, and SQS
events, it is very common to decode a `Decodable` body, or encode a
`Codable` type into a function URL response. This PR adds convenient
methods that are easy to use, but also maintain a level of customization
by allowing custom JSON encoders/decoders.

### Modifications:

* Add helper method to encode `Encodable` types into a
`FunctionURLReponse` or `APIGatewayV2Response`
* Add helper method do decode `Decodable` types from a
`FunctionURLRequest` or `APIGatewayV2Request`
* Add helper method to decode multiple `Decodable`s from `SQSEvent`
records, or from a single `SQSEvent.Message`
* Add test cases (generated with the help of LLM. Thanks Anthropic.
Verified tests pass after many tries, and went over the final changes to
make sure they're correct)

### Result:

The changes allow the following usage:

```swift
let decodedBody = try functionURLRequest.decode(MyPayload.self)
```

Instead of:

```swift
var bodyData = functionURLRequest.body?.data(using: .utf8) ?? Data()

// check for base 64 encoding of the body, and if that's the case, decode that into bodyData
if isBase64Encoded, let base64Decoded = ... {
   bodyData = base64Decoded
}

let decodedBody = JSONDecoder().decode(MyPayload.self, from: bodyData)
```
The same is similar when decoding SQS event messages.

And when encoding a response:

```swift
func handle(...) -> FunctionURLResponse {
    // business logic
    let responsePayload = MyResponse(text: "Hello Lambda", count: 613)
    return .encoding(responsePayload)
}
```

Instead of:
```swift
func handle(...) -> FunctionURLResponse {
    // business logic
    let responsePayload = MyResponse(text: "Hello Lambda", count: 613)
    do {
        let data = try JSONEncoder().encode(responsePayload)
        return .init(
            status: .ok,
            body: String(data: data, encoding: .utf8)
        }
    } catch {
        return .init(
            status: .internalServerError,
            body: "Internal server error: \(error)"
        }
    }
}
```
1.2.0
2025-08-06 16:36:05 +02:00
Sébastien Stormacq 9edb1f84a1 Add an init() that match the APIGatewayResponse (#91)
Add an `init()` to `FunctionURLResponse` to match the signature of
`APIGatewayv2Response`

### Motivation:

`APIGAtewayV2Response` and `FunctionURLResponse` share teh same
structure, although we provided two different signatures for the
initializers. This prevent writing common code to handle both responses.

### Modifications:

- add a new `init(0` that has the same signature as the init from
APIGatewayV2response
- make the current init as deprecated, we will remove it in a future
version bump

### Result:

Two init() functions on FunctionURLResponse
2025-08-06 15:50:21 +02:00
Sébastien Stormacq 856ab499b9 remove duplicate files 2025-06-30 21:57:28 +02:00
Richard Kendall Wolf 3967b151c5 Add (API Gateway) WebSockets Support to Swift for AWS Lambda Events (#38)
Add APIGateway WebSockets Event Type

### Motivation:

What I propose is adding WebSockets support to AWS Lambda Events.

Let me begin by stating outright that I am not sure this is the correct
approach to take to bring WebSockets to AWS Lambda Events. Therefore, if
this pull request is outright rejected, it won't hurt my feelings in the
slightest.

API Gateway supports not only RESTful APIs, but also WebSockets. The way
that it works is that API Gateway manages WebSockets sessions with
clients. Whenever a client sends API Gateway some WebSockets data, API
Gateway bundles it up in as an APIGatewayV2 request (at least, according
to Amazon) and passes it along to a designated target…usually a Lambda
function. This is what a bundled request looks like:

```javascript
{  
 headers: {
    Host: 'lqrlmblaa2.execute-api.us-east-1.amazonaws.com',
    Origin: 'wss://lqrlmblaa2.execute-api.us-east-1.amazonaws.com',
    'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits; server_max_window_bits=15',
    'Sec-WebSocket-Key': 'am5ubWVpbHd3bmNyYXF0ag==',
    'Sec-WebSocket-Version': '13',
    'X-Amzn-Trace-Id': 'Root=1-64b83950-42de8e247b4c2b43091ef67c',
    'X-Forwarded-For': '24.148.42.16',
    'X-Forwarded-Port': '443',
    'X-Forwarded-Proto': 'https'
  },
  multiValueHeaders: {
    Host: [ 'lqrlmblaa2.execute-api.us-east-1.amazonaws.com' ],
    Origin: [ 'wss://lqrlmblaa2.execute-api.us-east-1.amazonaws.com' ],
    'Sec-WebSocket-Extensions': [
      'permessage-deflate; client_max_window_bits; server_max_window_bits=15'
    ],
    'Sec-WebSocket-Key': [ 'am5ubWVpbHd3bmNyYXF0ag==' ],
    'Sec-WebSocket-Version': [ '13' ],
    'X-Amzn-Trace-Id': [ 'Root=1-64b83950-42de8e247b4c2b43091ef67c' ],
    'X-Forwarded-For': [ '24.148.42.16' ],
    'X-Forwarded-Port': [ '443' ],
    'X-Forwarded-Proto': [ 'https' ]
  },
  requestContext: {
    routeKey: '$connect',
    eventType: 'CONNECT',
    extendedRequestId: 'IU3kkGyEoAMFwZQ=',
    requestTime: '19/Jul/2023:19:28:16 +0000',
    messageDirection: 'IN',
    stage: 'dev',
    connectedAt: 1689794896145,
    requestTimeEpoch: 1689794896162,
    identity: { sourceIp: '24.148.42.16' },
    requestId: 'IU3kkGyEoAMFwZQ=',
    domainName: 'lqrlmblaa2.execute-api.us-east-1.amazonaws.com',
    connectionId: 'IU3kkeN4IAMCJwA=',
    apiId: 'lqrlmblaa2'
  },
  isBase64Encoded: false
}
```

The problem, of course, is that the current `APIGatewayV2Request` type
cannot decode that JSON because it is is missing a number of
non-optional data values that `APIGatewayV2Request` expects to exist
(e.g., `version`, `rawPath`, etc.).

There are (at least as far as I can tell) two solutions to make this
work. The first is simply to alter the current `APIGatewayV2Request` so
that a number of its data values become optionals. I resisted suggesting
this because I suspected it could easily break production code (forcing
developers to `if-let` things). I thought a better solution might simply
be to create a new request/response type pair that could accommodate
WebSockets APIs.

### Modifications:
I suggest adding a new event source file to AWS Lambda Events:
`APIGateway+WebSockets.swift` containing two new types:
`APIGatewayWebSocketRequest` and `APIGatewayWebSocketResponse`.
`APIGatewayWebSocketResponse` would simply be a type alias (since
responses require that no changes be made to that type);
`APIGatewayWebSocketRequest` would be capable of decoding the JSON
listed above.
A typical Lambda handler supporting WebSockets would look like this:

```swift
func handle(
  _ request: APIGatewayWebSocketRequest,
  context: LambdaContext
) async throws -> APIGatewayWebSocketResponse {

  let connectionID = request.context.connectionId
  let routeKey = request.context.routeKey
	
  // Route based on the type of WebSockets request
  // The following are "default" request types
  switch routeKey {
  case "$connect": break
  case "$disconnect": break
  case "$default":
    if let body = request.body {
    // Responses are sent to clients via the
    // ApiGatewayManagementApi. "post" is a method
    // (not shown) which does that
      try await post(
        message: "{\"echo\": \"\(body)\"}",
        toConnectionWithID: connectionID
      )
    }
    default:
      logger.log(level: .info, "Something weird happened");
    }

  // API Gateway requires that "some" status be returned
  // "no matter what"  
  return APIGatewayWebSocketResponse(statusCode: .ok)

}
```

Note that responses to WebSockets clients (including, potentially,
errors) are made through Amazon's `ApiGatewayManagementApi`. However,
API Gateway itself always expects some kind of response…this can be a
simple as always sending a 200 "OK" back to API Gateway.

### Result:
The Swift for AWS Lambda Runtime would be able to support API Gateway
WebSockets applications.

---------

Co-authored-by: Sébastien Stormacq <sebastien.stormacq@gmail.com>
1.1.0
2025-06-30 21:17:21 +02:00
Sébastien Stormacq 318868c10c [test] Migrate unit tests to Swift Testing (#88)
Migrate all unti tests to Swift Testing

### Motivation:

Allows to compile and run test on open source Swift toolchain 6

### Modifications:

Migrate according to 
https://developer.apple.com/documentation/testing/migratingfromxctest

### Result:

```
􁁛  Test run with 101 tests passed after 0.012 seconds.
```
2025-06-30 18:42:29 +02:00
Sébastien Stormacq 0025b1a409 Add an encodable version of the APIGatewayResponse (#86)
Add a convenience initializer to the APIGatewayResponse v2 that accepts
an Encodable object

### Motivation:

Most Lambda developers will return a JSON object when exposing their
function through the API Gateway. The current initializer only accepts a
`String` body as per the AWS message definition.

This obliges all developers to write two lines of code + error handling
to encode their object and transform the `Data` to a string.

### Modifications:

Add a new initializer that accepts a `body` as `Encodable`

```swift
public init<Input: Encodable> (
        statusCode: HTTPResponse.Status,
        headers: HTTPHeaders? = nil,
        body: Input,
        isBase64Encoded: Bool? = nil,
        cookies: [String]? = nil
) throws { ... }
```

### Result:

Developers can now pass a Swift struct to the APIGatewayResponse.

```swift
let businessResponse = BusinessResponse(message: "Hello World", code: 200)
return APIGatewayV2Response(statusCode: .ok, body: businessResponse)
```
1.0.0
2024-12-21 10:22:03 +01:00
Sébastien Stormacq 20fa5feaf0 Update .gitignore to ignore .devcontainer (#84)
`.devcontainer` should not be versioned to allow developers to customize
it without git to interfere
2024-12-19 18:50:02 +01:00
Tobias 7bcecc571d Use only FoundationEssentials when possible (#81)
Linking against `Foundation` on linux adds a hefty binary size penalty.
Mostly due to the ICU data from `FoundationInternationalization`. To
address this we conditionally import `FoundationEssentials` instead of
`Foundation` if possible and replace `Foundation`-only API with a
different implementation.

### Motivation:

Smaller binary sizes are better.

### Modifications:

- Replace `import Foundation` with `import FoundationEssentials`.
- Update date parsing logic to use newer API if available.
- Implement a custom parser for RFC5322 dates

### Result:

Ability to build the package without linking `Foundation`.

---------

Co-authored-by: Sébastien Stormacq <sebastien.stormacq@gmail.com>
2024-12-19 17:55:31 +01:00
Tobias d2761dc5b5 Adds devcontainer config (#82)
Adds default devcontainer configuration from SSWG:
https://github.com/swift-server/swift-devcontainer-template

### Motivation:

Developing for linux can be challenging on macOS because some APIs are
not available on Linux. By using VSCode and devcontainer you can
essentially develop "on linux".

### Modifications:

Adds devcontainer config.

### Result:

When working in VSCode, you can now easily open the project inside a
devcontainer.

Co-authored-by: Sébastien Stormacq <sebastien.stormacq@gmail.com>
2024-12-19 11:50:54 +01:00
Franz Busch 18c4c26faf Update release.yml (#83)
Update the release.yml file with the latest label changes
2024-12-18 14:32:19 +01:00
Sébastien Stormacq 334d865f8a Add custom Decodable conformance (#80)
Add custom Decodable conformance.
Closes https://github.com/swift-server/swift-aws-lambda-events/issues/73
Duplicate of
https://github.com/swift-server/swift-aws-lambda-events/pull/76 created
by @twistinside

**Motivation:**
Absent collections would fail to decode, when in reality it is possible
to have empty headers, for example. This allows processing to continue
in the context of the Lambda runtime where users can handle the
collections as dictated by their code.

**Modifications:**
Custom Decodable conformance has been added to both API Gateway request
objects to optionally decode absent collections to empty collections.

Unit testa have been added for the same.

**Result:**
This will make the swift lambda runtime more accepting of input,
allowing processing to proceed in the rare cases where collection fields
would be absent in the JSON received by the runtime. This will unlock
certain functionality in edge cases such as testing lambda code from API
Gateway console with empty headers (the use case that prompted this
change).

This change will require users to update their code to remove optional
handling for the collections involved, potentially also requiring extra
logic to validate that the collections they've received aren't empty.

---------

Authored-by: twistinside <twistinside@users.noreply.github.com>
2024-12-03 23:55:08 +01:00
jsonfry 3c1161a2e0 Make S3 eTag optional (#78)
Make S3 Object eTag optional, because it's not always there.

### Motivation:

I'm seeing real events without an eTag, which naturally is causing
decoding failures.

### Modifications:

Made S3 Object eTag optional.

### Result:

S3 Object eTag is now optional...
2024-12-02 21:21:06 +01:00
Sébastien Stormacq ee11dac0bf fix CI (#77)
* add semantic version check

* disable yaml linter

* Disable Swift 5.8 unit test

* re-enable additional soundness checks

* fix shell scripts

* fix yaml lint
2024-11-26 15:31:20 +01:00
Sébastien Stormacq 7bb1b04d95 add .index-build to gitignore (#74) 2024-11-12 10:08:37 +01:00
Sébastien Stormacq bbd2810b16 Fix CI (#72)
* fix ci, use swiftlang workflows

* typo

* typo

* fix format

* use 6.0-noble for format check

* fix format
2024-11-08 00:25:53 +01:00
Ugo Cottin cfd688e499 Add EventBridge S3Events notifications (#70) 0.5.0 2024-11-07 23:22:13 +01:00
jsonfry 906610f502 CognitoEvent CallerContext ClientId should be optional (#71) 2024-11-07 23:12:33 +01:00
Sébastien Stormacq 2d9612d6bf Fix https://github.com/swift-server/swift-aws-lambda-events/issues/58 2024-11-07 23:10:04 +01:00
Adolfo 32a1d03b9b AWS Regions. Summer 2024 (#59)
* Added the new AWS regions availables

* Adding new AWS regions

* Fix the variable declaration
2024-11-07 22:54:31 +01:00
Sébastien Stormacq ec7e66d58a improve name for default base64 alphabet (#69) 2024-10-08 13:39:51 +02:00
Sébastien Stormacq 8fc6d4eecb remove Example dir (#68)
* link to up-to-date tutorial

* remove examples dir

* add swift-format config

* remove NoAssignmentInExpressions linter warning

* remove DontRepeatTypeInStaticProperties linter warning
2024-10-08 13:31:40 +02:00
Fabian Fett 79db2aa207 Ensure Events still compiles (#67)
* Ensure Events still compiles

* Fix unacceptable language

* Fix more

* swift-format

* Fix docs?

* Fix license check
2024-10-08 12:47:48 +02:00
Fabian Fett a61f77e021 Use FoundationEssentials if possible (#64) 2024-09-30 17:54:01 +02:00
Fabian Fett fe1b1f8237 Use GitHub actions for CI (#65) 2024-09-30 17:53:34 +02:00
Fabian Fett 8c8bc1e381 Restructure Package.swift (#63) 2024-09-30 16:58:56 +02:00
Fabian Fett 3509a89083 Remove LinuxMain (#62) 2024-09-30 15:59:48 +02:00
jsonfry a0b64e9d0d Cognito Triggers - PreSignUp, PostConfirmation, PostAuthentication, CustomMessage (#57)
* More Cognito events

- PostConfirmation
- PostAuthentication
- CustomMessage
0.4.0
2024-06-12 09:37:38 +02:00
Sébastien Stormacq eb8852268e add support for BedrockAgents (#55)
* add support for BedrockAgents

* fix soudness
2024-06-05 15:39:39 +02:00
Alessio Buratti 212c6dc5e7 Add support for multi-resource statements (#52) 2024-05-29 20:09:26 +02:00
Sébastien Stormacq 2c04633217 cleanup pre Swift 5.6 code (#51)
remove "if swift(>=5.6)" statements and move Sendable up to the struct definition
2024-05-29 15:22:00 +02:00
Sébastien Stormacq 99a3bf1404 addopt strict concurrency (#50)
* remove support for versions of Swift <= 5.6

* Simplify the Package.swift for older Swift versions

* bump swift version on example project 

* add StrictConcurrency to prepare for Swift 6with  StrictConcurrency=complete syntax

* use a computed property for dateformatter

* refine CloudwatchDetail for Sendable conformance
2024-05-28 10:07:02 +02:00
Sébastien Stormacq 5de630dd3c remove support for versions of Swift <= 5.6 (#49)
* remove support for versions of Swift <= 5.6
* Simplify the Package.swift for older Swift versions
* bump swift version on example project and Dockerfile
2024-05-24 11:15:51 +02:00
jsonfry f015dbfffa Use Swift HTTP types package for status and method (#47)
* Use Swift HTTP types package for status and method

* Fix formatting
0.3.0
2024-05-23 10:30:39 +02:00
Simon Leeb 5b4633d1cc Add mTLS client certificate information to APIGatwayV2Request (#45)
* added authentication and clientCert to APIGatwayV2Request

* added clientCert unit test
2024-02-13 08:58:55 -08:00