Skip to content

Commit

Permalink
Merge pull request #26 from noppoMan/support-hal-json
Browse files Browse the repository at this point in the history
support application/hal+json response
  • Loading branch information
noppoMan authored May 16, 2017
2 parents 06aef27 + 2d8cc14 commit 1eb41cd
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 285 deletions.
6 changes: 6 additions & 0 deletions Package.pins
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
"repositoryURL": "https://github.com/vapor/clibressl.git",
"version": "1.0.0"
},
{
"package": "HypertextApplicationLanguage",
"reason": null,
"repositoryURL": "https://github.com/noppoMan/HypertextApplicationLanguage.git",
"version": "1.0.1"
},
{
"package": "Prorsum",
"reason": null,
Expand Down
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ let package = Package(
dependencies: [
.Package(url: "https://github.com/vapor/clibressl.git", majorVersion: 1),
.Package(url: "https://github.com/IBM-Swift/SwiftyJSON.git", majorVersion: 16),
.Package(url: "https://github.com/noppoMan/Prorsum.git", majorVersion: 0, minor: 1)
.Package(url: "https://github.com/noppoMan/Prorsum.git", majorVersion: 0, minor: 1),
.Package(url: "https://github.com/noppoMan/HypertextApplicationLanguage.git", majorVersion: 1)
]
)
462 changes: 231 additions & 231 deletions Sources/AWSSDKSwift/Services/apigateway/Apigateway_Shapes.swift

Large diffs are not rendered by default.

64 changes: 27 additions & 37 deletions Sources/CodeGenerator/CodeGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,23 +96,6 @@ extension Member {
let defaultArgument = required ? "" : " = nil"
return "\(name.toSwiftLabelCase()): \(swiftTypeName)\(optionalSuffix)\(defaultArgument)"
}

func guardStatement() -> String {
switch shape.type {
case .structure(_), .map(_):
return "guard let \(variableName) = dictionary[\"\(pathForLocation)\"] as? [String: Any] else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }"

case .list(let shape):
switch shape.type {
case .structure(_), .map(_):
return "guard let \(variableName) = dictionary[\"\(pathForLocation)\"] as? [[String: Any]] else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }"
default:
return "guard let \(variableName) = dictionary[\"\(pathForLocation)\"] as? [\(shape.swiftTypeName)] else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }"
}
default:
return "guard let \(variableName) = dictionary[\"\(pathForLocation)\"] as? \(shape.swiftTypeName) else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }"
}
}
}

extension AWSService {
Expand Down Expand Up @@ -217,24 +200,31 @@ extension AWSService {
code += "\(indt(2))public init(dictionary: [String: Any]) throws {\n"

for member in structure.members {
let pathForLocation: String
if Core.jsonKeyStyle(forService: endpointPrefix).isCamelCase {
pathForLocation = member.locationName?.upperFirst() ?? member.name
} else {
pathForLocation = member.locationName ?? member.name
}

switch member.shape.type {
case .structure(_):
let substituting = "self.\(member.variableName) = try \(serviceName).\(member.swiftTypeName)(dictionary: \(member.variableName))"

if member.required {
code += "\(indt(3))\(member.guardStatement())"
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? [String: Any] else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }"
code += "\n"
code += indt(3)+substituting
} else {
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? [String: Any] { \(substituting) } else { self.\(member.variableName) = nil }"
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? [String: Any] { \(substituting) } else { self.\(member.variableName) = nil }"
}
code += "\n"
case .enum:
if member.required {
code += "\(indt(3))guard let raw\(member.name) = dictionary[\"\(member.pathForLocation)\"] as? String, let \(member.variableName) = \(member.shape.swiftTypeName.toSwiftClassCase())(rawValue: raw\(member.name)) else { throw InitializableError.missingRequiredParam(\"\(member.pathForLocation)\") }\n"
code += "\(indt(3))guard let raw\(member.name) = dictionary[\"\(pathForLocation)\"] as? String, let \(member.variableName) = \(member.shape.swiftTypeName.toSwiftClassCase())(rawValue: raw\(member.name)) else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }\n"
code += indt(3)+"self.\(member.variableName) = \(member.variableName)"
} else {
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? String { self.\(member.variableName) = \(member.shape.swiftTypeName.toSwiftClassCase())(rawValue: \(member.variableName)) } else { self.\(member.variableName) = nil }"
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? String { self.\(member.variableName) = \(member.shape.swiftTypeName.toSwiftClassCase())(rawValue: \(member.variableName)) } else { self.\(member.variableName) = nil }"
}
code += "\n"

Expand Down Expand Up @@ -375,10 +365,10 @@ extension AWSService {

if let decodingCode = decodingCode {
if member.required {
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? \(firstElementType) else { throw InitializableError.missingRequiredParam(\"\(member.pathForLocation)\") }\n"
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? \(firstElementType) else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }\n"
code += decodingCode(3)
} else {
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? \(firstElementType) {\n"
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? \(firstElementType) {\n"
code += decodingCode(4)
code += "\(indt(3))} else { \n"
code += "\(indt(4))self.\(member.variableName) = nil\n"
Expand All @@ -391,19 +381,19 @@ extension AWSService {
case .enum(_):
let substituting = "self.\(member.variableName) = \(member.variableName).flatMap({ \(shape.swiftTypeName.toSwiftClassCase())(rawValue: $0)})"
if member.required {
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? [String] else { throw InitializableError.missingRequiredParam(\"\(member.pathForLocation)\") }\n"
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? [String] else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }\n"
code += indt(3)+substituting
} else {
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? [String] { \(substituting) } else { self.\(member.variableName) = nil }"
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? [String] { \(substituting) } else { self.\(member.variableName) = nil }"
}
code += "\n"

case .structure:
if member.required {
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? [[String: Any]] else { throw InitializableError.missingRequiredParam(\"\(member.pathForLocation)\") }\n"
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? [[String: Any]] else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }\n"
code += "\(indt(3))self.\(member.variableName) = try \(member.variableName).map({ try \(shape.swiftTypeName)(dictionary: $0) })\n"
} else {
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? [[String: Any]] {\n"
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? [[String: Any]] {\n"
code += "\(indt(4))self.\(member.variableName) = try \(member.variableName).map({ try \(shape.swiftTypeName)(dictionary: $0) })\n"
code += "\(indt(3))} else { \n"
code += "\(indt(4))self.\(member.variableName) = nil\n"
Expand Down Expand Up @@ -431,10 +421,10 @@ extension AWSService {
}

if member.required {
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? [[String: [String: Any]]] else { throw InitializableError.missingRequiredParam(\"\(member.pathForLocation)\") }\n"
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? [[String: [String: Any]]] else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }\n"
code += decodingCode(3)
} else {
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? [[String: [String: Any]]] {\n"
code += "\(indt(3))if let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? [[String: [String: Any]]] {\n"
code += decodingCode(4)
code += "\(indt(3))} else { \n"
code += "\(indt(4))self.\(member.variableName) = nil\n"
Expand All @@ -445,10 +435,10 @@ extension AWSService {

default:
if member.required {
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? \(member.swiftTypeName) else { throw InitializableError.missingRequiredParam(\"\(member.name)\") }\n"
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? \(member.swiftTypeName) else { throw InitializableError.missingRequiredParam(\"\(member.name)\") }\n"
code += "\(indt(3))self.\(member.variableName) = \(member.variableName)\n"
} else {
code += "\(indt(3))self.\(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? \(member.swiftTypeName)\n"
code += "\(indt(3))self.\(member.variableName) = dictionary[\"\(pathForLocation)\"] as? \(member.swiftTypeName)\n"
}
}
case .list(let childShape):
Expand All @@ -458,27 +448,27 @@ extension AWSService {

default:
if member.required {
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? \(member.swiftTypeName) else { throw InitializableError.missingRequiredParam(\"\(member.pathForLocation)\") }\n"
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? \(member.swiftTypeName) else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }\n"
code += "\(indt(3))self.\(member.variableName) = \(member.variableName)\n"
} else {
code += "\(indt(3))self.\(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? \(member.swiftTypeName)\n"
code += "\(indt(3))self.\(member.variableName) = dictionary[\"\(pathForLocation)\"] as? \(member.swiftTypeName)\n"
}
}
default:
if member.required {
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? \(member.swiftTypeName) else { throw InitializableError.missingRequiredParam(\"\(member.pathForLocation)\") }\n"
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? \(member.swiftTypeName) else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }\n"
code += "\(indt(3))self.\(member.variableName) = \(member.variableName)\n"
} else {
code += "\(indt(3))self.\(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? \(member.swiftTypeName)\n"
code += "\(indt(3))self.\(member.variableName) = dictionary[\"\(pathForLocation)\"] as? \(member.swiftTypeName)\n"
}
}

default:
if member.required {
code += "\(indt(3))\(member.guardStatement())\n"
code += "\(indt(3))guard let \(member.variableName) = dictionary[\"\(pathForLocation)\"] as? \(member.swiftTypeName) else { throw InitializableError.missingRequiredParam(\"\(pathForLocation)\") }\n"
code += "\(indt(3))self.\(member.variableName) = \(member.variableName)\n"
} else {
code += "\(indt(3))self.\(member.variableName) = dictionary[\"\(member.pathForLocation)\"] as? \(member.swiftTypeName)\n"
code += "\(indt(3))self.\(member.variableName) = dictionary[\"\(pathForLocation)\"] as? \(member.swiftTypeName)\n"
}
}
}
Expand Down
43 changes: 32 additions & 11 deletions Sources/Core/AWSClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Foundation
import Dispatch
import SwiftyJSON
import Prorsum
import HypertextApplicationLanguage

extension Characters {
public static let uriAWSQueryAllowed: Characters = ["!", "$", "&", "\'", "(", ")", "+", "-", ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "=", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "_", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
Expand All @@ -32,16 +33,16 @@ public struct InputContext {
let input: AWSShape
}

public struct AWSClient {
var jsonKeyStyle: DictionaryKeyStyle {
switch signer.service {
case "apigateway":
return .pascal
default:
return .camel
}
public func jsonKeyStyle(forService service: String) -> DictionaryKeyStyle {
switch service {
case "apigateway":
return .pascal
default:
return .camel
}

}

public struct AWSClient {
let signer: Signers.V4

let apiVersion: String
Expand Down Expand Up @@ -182,8 +183,28 @@ public struct AWSClient {
if !data.isEmpty {
switch serviceProtocol {
case .json, .restjson:
if let dictionary = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
if let cType = response.contentType, cType.subtype.contains("hal+json") {
var dictionary: [String: Any] = [:]
let representation = try Representation.from(json: data)
for rel in representation.rels {
guard let representations = try Representation.from(json: data).representations(for: rel) else {
continue
}

let isArray = representation.links.filter({ $0.rel == rel }).count > 1

if isArray {
dictionary[rel] = representations.map({ $0.properties })
} else {
dictionary[rel] = representations.map({ $0.properties }).first ?? [:]
}
}
responseBody = .json(dictionary)

} else {
if let dictionary = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
responseBody = .json(dictionary)
}
}

case .restxml, .query:
Expand Down Expand Up @@ -340,7 +361,7 @@ public struct AWSClient {
body = Body(anyValue: payloadBody)
headers.removeValue(forKey: payload.toSwiftVariableCase())
} else {
body = .json(try ctx.input.serializeToDictionary(keyStyle: jsonKeyStyle))
body = .json(try ctx.input.serializeToDictionary(keyStyle: jsonKeyStyle(forService: signer.service)))
}

case .query:
Expand Down
4 changes: 0 additions & 4 deletions Sources/Core/Doc/Member.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ public struct Member {
public let xmlNamespace: XMLNamespace?
public let isStreaming: Bool

public var pathForLocation: String {
return locationName?.upperFirst() ?? name
}

public init(name: String, required: Bool, shape: Shape, location: Location?, locationName: String?, xmlNamespace: XMLNamespace?, isStreaming: Bool){
self.name = name
self.required = required
Expand Down
2 changes: 1 addition & 1 deletion Sources/Core/Serializer/Serializable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public enum DictionaryKeyStyle {
case camel
case pascal

var isCamelCase: Bool {
public var isCamelCase: Bool {
switch self {
case .camel:
return true
Expand Down

0 comments on commit 1eb41cd

Please sign in to comment.