Skip to content

Commit 8649522

Browse files
Refactor ProductService and ProductLambdaHandler
1 parent e123d60 commit 8649522

File tree

2 files changed

+81
-172
lines changed

2 files changed

+81
-172
lines changed

Examples/LambdaFunctions/Sources/ProductAPI/ProductLambdaHandler.swift

Lines changed: 60 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -26,186 +26,84 @@ struct ProductLambdaHandler: EventLoopLambdaHandler {
2626
let operation: Operation
2727

2828
func handle(context: Lambda.Context, event: APIGateway.V2.Request) -> EventLoopFuture<APIGateway.V2.Response> {
29-
30-
switch operation {
31-
case .create:
32-
let create = CreateLambdaHandler(service: service).handle(context: context, event: event)
33-
.flatMap { response -> EventLoopFuture<APIGateway.V2.Response> in
34-
switch response {
35-
case .success(let result):
36-
let value = APIGateway.V2.Response(with: result, statusCode: .created)
37-
return context.eventLoop.makeSucceededFuture(value)
38-
case .failure(let error):
39-
let value = APIGateway.V2.Response(with: error, statusCode: .forbidden)
40-
return context.eventLoop.makeSucceededFuture(value)
41-
}
42-
}
43-
return create
44-
case .read:
45-
let read = ReadLambdaHandler(service: service).handle(context: context, event: event)
46-
.flatMap { response -> EventLoopFuture<APIGateway.V2.Response> in
47-
switch response {
48-
case .success(let result):
49-
let value = APIGateway.V2.Response(with: result, statusCode: .ok)
50-
return context.eventLoop.makeSucceededFuture(value)
51-
case .failure(let error):
52-
let value = APIGateway.V2.Response(with: error, statusCode: .notFound)
53-
return context.eventLoop.makeSucceededFuture(value)
54-
}
55-
}
56-
return read
57-
case .update:
58-
let update = UpdateLambdaHandler(service: service).handle(context: context, event: event)
59-
.flatMap { response -> EventLoopFuture<APIGateway.V2.Response> in
60-
switch response {
61-
case .success(let result):
62-
let value = APIGateway.V2.Response(with: result, statusCode: .ok)
63-
return context.eventLoop.makeSucceededFuture(value)
64-
case .failure(let error):
65-
let value = APIGateway.V2.Response(with: error, statusCode: .notFound)
66-
return context.eventLoop.makeSucceededFuture(value)
67-
}
68-
}
69-
return update
70-
case .delete:
71-
let delete = DeleteUpdateLambdaHandler(service: service).handle(
72-
context: context, event: event
73-
)
74-
.flatMap { response -> EventLoopFuture<APIGateway.V2.Response> in
75-
switch response {
76-
case .success(let result):
77-
let value = APIGateway.V2.Response(with: result, statusCode: .ok)
78-
return context.eventLoop.makeSucceededFuture(value)
79-
case .failure(let error):
80-
let value = APIGateway.V2.Response(with: error, statusCode: .notFound)
81-
return context.eventLoop.makeSucceededFuture(value)
82-
}
83-
}
84-
return delete
85-
case .list:
86-
let list = ListUpdateLambdaHandler(service: service).handle(context: context, event: event)
87-
.flatMap { response -> EventLoopFuture<APIGateway.V2.Response> in
88-
switch response {
89-
case .success(let result):
90-
let value = APIGateway.V2.Response(with: result, statusCode: .ok)
91-
return context.eventLoop.makeSucceededFuture(value)
92-
case .failure(let error):
93-
let value = APIGateway.V2.Response(with: error, statusCode: .forbidden)
94-
return context.eventLoop.makeSucceededFuture(value)
95-
}
96-
}
97-
return list
98-
}
29+
30+
switch self.operation {
31+
case .create:
32+
return createLambdaHandler(context: context, event: event)
33+
case .read:
34+
return readLambdaHandler(context: context, event: event)
35+
case .update:
36+
return updateLambdaHandler(context: context, event: event)
37+
case .delete:
38+
return deleteUpdateLambdaHandler(context: context, event: event)
39+
case .list:
40+
return listUpdateLambdaHandler(context: context, event: event)
41+
}
9942
}
10043

101-
struct CreateLambdaHandler {
102-
103-
let service: ProductService
104-
105-
init(service: ProductService) {
106-
self.service = service
44+
func createLambdaHandler(context: Lambda.Context, event: APIGateway.V2.Request) -> EventLoopFuture<APIGateway.V2.Response> {
45+
guard let product: Product = try? event.object() else {
46+
let error = APIError.invalidRequest
47+
return context.eventLoop.makeFailedFuture(error)
10748
}
108-
109-
func handle(context: Lambda.Context, event: APIGateway.V2.Request) -> EventLoopFuture<Result<Product, Error>> {
110-
111-
guard let product: Product = try? event.object() else {
112-
let error = APIError.invalidRequest
113-
return context.eventLoop.makeFailedFuture(error)
114-
}
115-
let future = service.createItem(product: product)
116-
.flatMapThrowing { item -> Result<Product, Error> in
117-
return Result.success(product)
118-
}
119-
return future
49+
return service.createItem(product: product)
50+
.map { result -> (APIGateway.V2.Response) in
51+
return APIGateway.V2.Response(with: result, statusCode: .created)
52+
}.flatMapError { (error) -> EventLoopFuture<APIGateway.V2.Response> in
53+
let value = APIGateway.V2.Response(with: error, statusCode: .forbidden)
54+
return context.eventLoop.makeSucceededFuture(value)
12055
}
12156
}
12257

123-
struct ReadLambdaHandler {
124-
125-
let service: ProductService
126-
127-
init(service: ProductService) {
128-
self.service = service
58+
func readLambdaHandler(context: Lambda.Context, event: APIGateway.V2.Request) -> EventLoopFuture<APIGateway.V2.Response> {
59+
guard let sku = event.pathParameters?["sku"] else {
60+
let error = APIError.invalidRequest
61+
return context.eventLoop.makeFailedFuture(error)
12962
}
130-
131-
func handle(context: Lambda.Context, event: APIGateway.V2.Request) -> EventLoopFuture<Result<Product, Error>> {
132-
133-
guard let sku = event.pathParameters?["sku"] else {
134-
let error = APIError.invalidRequest
135-
return context.eventLoop.makeFailedFuture(error)
136-
}
137-
let future = service.readItem(key: sku)
138-
.flatMapThrowing { data -> Result<Product, Error> in
139-
let product = try Product(dictionary: data.item ?? [:])
140-
return Result.success(product)
141-
}
142-
return future
63+
return service.readItem(key: sku)
64+
.flatMapThrowing { result -> APIGateway.V2.Response in
65+
return APIGateway.V2.Response(with: result, statusCode: .ok)
66+
}.flatMapError { (error) -> EventLoopFuture<APIGateway.V2.Response> in
67+
let value = APIGateway.V2.Response(with: error, statusCode: .notFound)
68+
return context.eventLoop.makeSucceededFuture(value)
14369
}
14470
}
14571

146-
struct UpdateLambdaHandler {
147-
148-
let service: ProductService
149-
150-
init(service: ProductService) {
151-
self.service = service
72+
func updateLambdaHandler(context: Lambda.Context, event: APIGateway.V2.Request) -> EventLoopFuture<APIGateway.V2.Response> {
73+
guard let product: Product = try? event.object() else {
74+
let error = APIError.invalidRequest
75+
return context.eventLoop.makeFailedFuture(error)
15276
}
153-
154-
func handle(context: Lambda.Context, event: APIGateway.V2.Request) -> EventLoopFuture<Result<Product, Error>> {
155-
156-
guard let product: Product = try? event.object() else {
157-
let error = APIError.invalidRequest
158-
return context.eventLoop.makeFailedFuture(error)
159-
}
160-
let future = service.updateItem(product: product)
161-
.flatMapThrowing { (data) -> Result<Product, Error> in
162-
return Result.success(product)
163-
}
164-
return future
77+
return service.updateItem(product: product)
78+
.map { result -> (APIGateway.V2.Response) in
79+
return APIGateway.V2.Response(with: result, statusCode: .ok)
80+
}.flatMapError { (error) -> EventLoopFuture<APIGateway.V2.Response> in
81+
let value = APIGateway.V2.Response(with: error, statusCode: .notFound)
82+
return context.eventLoop.makeSucceededFuture(value)
16583
}
16684
}
16785

168-
struct DeleteUpdateLambdaHandler {
169-
170-
let service: ProductService
171-
172-
init(service: ProductService) {
173-
self.service = service
86+
func deleteUpdateLambdaHandler(context: Lambda.Context, event: APIGateway.V2.Request) -> EventLoopFuture<APIGateway.V2.Response> {
87+
guard let sku = event.pathParameters?["sku"] else {
88+
let error = APIError.invalidRequest
89+
return context.eventLoop.makeFailedFuture(error)
17490
}
175-
176-
func handle(context: Lambda.Context, event: APIGateway.V2.Request) -> EventLoopFuture<Result<EmptyResponse, Error>> {
177-
178-
guard let sku = event.pathParameters?["sku"] else {
179-
let error = APIError.invalidRequest
180-
return context.eventLoop.makeFailedFuture(error)
181-
}
182-
let future = service.deleteItem(key: sku)
183-
.flatMapThrowing { (data) -> Result<EmptyResponse, Error> in
184-
return Result.success(EmptyResponse())
185-
}
186-
return future
91+
return service.deleteItem(key: sku)
92+
.map { _ -> (APIGateway.V2.Response) in
93+
return APIGateway.V2.Response(with: EmptyResponse(), statusCode: .ok)
94+
}.flatMapError { (error) -> EventLoopFuture<APIGateway.V2.Response> in
95+
let value = APIGateway.V2.Response(with: error, statusCode: .notFound)
96+
return context.eventLoop.makeSucceededFuture(value)
18797
}
18898
}
18999

190-
struct ListUpdateLambdaHandler {
191-
192-
let service: ProductService
193-
194-
init(service: ProductService) {
195-
self.service = service
196-
}
197-
198-
func handle(context: Lambda.Context, event: APIGateway.V2.Request) -> EventLoopFuture<Result<[Product], Error>> {
199-
200-
let future = service.listItems()
201-
.flatMapThrowing { data -> Result<[Product], Error> in
202-
let products: [Product]? = try data.items?.compactMap { (item) -> Product in
203-
return try Product(dictionary: item)
204-
}
205-
let object = products ?? []
206-
return Result.success(object)
207-
}
208-
return future
100+
func listUpdateLambdaHandler(context: Lambda.Context, event: APIGateway.V2.Request) -> EventLoopFuture<APIGateway.V2.Response> {
101+
return service.listItems()
102+
.flatMapThrowing { result -> APIGateway.V2.Response in
103+
return APIGateway.V2.Response(with: result, statusCode: .ok)
104+
}.flatMapError { (error) -> EventLoopFuture<APIGateway.V2.Response> in
105+
let value = APIGateway.V2.Response(with: error, statusCode: .forbidden)
106+
return context.eventLoop.makeSucceededFuture(value)
209107
}
210108
}
211109
}

Examples/LambdaFunctions/Sources/ProductAPI/ProductService.swift

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class ProductService {
4242
self.tableName = tableName
4343
}
4444

45-
public func createItem(product: Product) -> EventLoopFuture<DynamoDB.PutItemOutput> {
45+
public func createItem(product: Product) -> EventLoopFuture<Product> {
4646

4747
var product = product
4848
let date = Date().iso8601
@@ -53,19 +53,22 @@ public class ProductService {
5353
item: product.dynamoDictionary,
5454
tableName: tableName
5555
)
56-
return db.putItem(input)
56+
return db.putItem(input).flatMap { _ -> EventLoopFuture<Product> in
57+
return self.readItem(key: product.sku)
58+
}
5759
}
5860

59-
public func readItem(key: String) -> EventLoopFuture<DynamoDB.GetItemOutput> {
61+
public func readItem(key: String) -> EventLoopFuture<Product> {
6062
let input = DynamoDB.GetItemInput(
6163
key: [ProductField.sku: DynamoDB.AttributeValue(s: key)],
6264
tableName: tableName
6365
)
64-
return db.getItem(input)
66+
return db.getItem(input).flatMapThrowing { data -> Product in
67+
return try Product(dictionary: data.item ?? [:])
68+
}
6569
}
6670

67-
public func updateItem(product: Product) -> EventLoopFuture<DynamoDB.UpdateItemOutput> {
68-
71+
public func updateItem(product: Product) -> EventLoopFuture<Product> {
6972
var product = product
7073
let date = Date().iso8601
7174
product.updatedAt = date
@@ -86,19 +89,27 @@ public class ProductService {
8689
tableName: tableName,
8790
updateExpression: "SET #name = :name, #description = :description, #updatedAt = :updatedAt"
8891
)
89-
return db.updateItem(input)
92+
return db.updateItem(input).flatMap { _ -> EventLoopFuture<Product> in
93+
return self.readItem(key: product.sku)
94+
}
9095
}
9196

92-
public func deleteItem(key: String) -> EventLoopFuture<DynamoDB.DeleteItemOutput> {
97+
public func deleteItem(key: String) -> EventLoopFuture<Void> {
9398
let input = DynamoDB.DeleteItemInput(
9499
key: [ProductField.sku: DynamoDB.AttributeValue(s: key)],
95100
tableName: tableName
96101
)
97-
return db.deleteItem(input)
102+
return db.deleteItem(input).map { _ in Void() }
98103
}
99104

100-
public func listItems() -> EventLoopFuture<DynamoDB.ScanOutput> {
105+
public func listItems() -> EventLoopFuture<[Product]> {
101106
let input = DynamoDB.ScanInput(tableName: tableName)
102107
return db.scan(input)
108+
.flatMapThrowing { data -> [Product] in
109+
let products: [Product]? = try data.items?.compactMap { (item) -> Product in
110+
return try Product(dictionary: item)
111+
}
112+
return products ?? []
113+
}
103114
}
104115
}

0 commit comments

Comments
 (0)