Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Representor.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = 'Representor'
spec.version = '0.7.2'
spec.version = '0.7.3'
spec.summary = 'A canonical resource object interface in Swift.'
spec.homepage = 'https://github.com/the-hypermedia-project/representor-swift'
spec.license = { :type => 'MIT', :file => 'LICENSE' }
Expand Down
16 changes: 15 additions & 1 deletion Representor.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
0D035D751CB4FA2000DC31F4 /* link-objects.hal.json in Resources */ = {isa = PBXBuildFile; fileRef = 0D035D741CB4FA2000DC31F4 /* link-objects.hal.json */; };
271629B71C4011D40027A90C /* RepresentorBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271629B51C4011D40027A90C /* RepresentorBuilder.swift */; };
271629B81C4011D40027A90C /* TransitionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271629B61C4011D40027A90C /* TransitionBuilder.swift */; };
271629BB1C40125A0027A90C /* HTTPHALAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271629B91C40125A0027A90C /* HTTPHALAdapter.swift */; };
Expand Down Expand Up @@ -46,6 +47,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
0D035D741CB4FA2000DC31F4 /* link-objects.hal.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "link-objects.hal.json"; sourceTree = "<group>"; };
271629B51C4011D40027A90C /* RepresentorBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepresentorBuilder.swift; sourceTree = "<group>"; };
271629B61C4011D40027A90C /* TransitionBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitionBuilder.swift; sourceTree = "<group>"; };
271629B91C40125A0027A90C /* HTTPHALAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPHALAdapter.swift; path = Sources/HTTPHALAdapter.swift; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -260,6 +262,7 @@
276A2C071A7BA500004BCC6F /* blueprint.json */,
77F592341A1B6E1B0070F839 /* poll.hal.json */,
77F592351A1B6E1B0070F839 /* poll.siren.json */,
0D035D741CB4FA2000DC31F4 /* link-objects.hal.json */,
);
path = Fixtures;
sourceTree = "<group>";
Expand Down Expand Up @@ -322,14 +325,16 @@
attributes = {
LastSwiftMigration = 0700;
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0700;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = Apiary;
TargetAttributes = {
770834621A0913860008869E = {
CreatedOnToolsVersion = 6.1;
LastSwiftMigration = 0800;
};
7708346D1A0913860008869E = {
CreatedOnToolsVersion = 6.1;
LastSwiftMigration = 0800;
};
};
};
Expand Down Expand Up @@ -366,6 +371,7 @@
77F592371A1B6E1B0070F839 /* poll.hal.json in Resources */,
77F592381A1B6E1B0070F839 /* poll.siren.json in Resources */,
276A2C081A7BA500004BCC6F /* blueprint.json in Resources */,
0D035D751CB4FA2000DC31F4 /* link-objects.hal.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -441,6 +447,7 @@
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
Expand Down Expand Up @@ -486,6 +493,7 @@
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
Expand Down Expand Up @@ -518,6 +526,7 @@
PRODUCT_NAME = Representor;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 2.3;
};
name = Debug;
};
Expand All @@ -538,6 +547,8 @@
PRODUCT_BUNDLE_IDENTIFIER = "io.apiary.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = Representor;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 2.3;
};
name = Release;
};
Expand All @@ -554,6 +565,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "io.apiary.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = RepresentorTests;
SWIFT_VERSION = 2.3;
};
name = Debug;
};
Expand All @@ -566,6 +578,8 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "io.apiary.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = RepresentorTests;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 2.3;
};
name = Release;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
23 changes: 21 additions & 2 deletions Sources/HTTPHALAdapter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,38 @@

import Foundation

/// https://tools.ietf.org/html/draft-kelly-json-hal-07#section-5.5
private let AllowedHALLinkOptions = [
"templated", "type", "deprecation",
"name", "profile", "title", "hreflang"
]

private func parseHALLinkAttributes(options: [String:AnyObject], builder: HTTPTransitionBuilder) {
for (key, value) in options {
guard AllowedHALLinkOptions.contains(key) else { continue }
builder.addAttribute(key, title: nil, value: value, defaultValue: nil, required: nil)
}
}

func parseHALLinks(halLinks:[String:AnyObject]) -> [String:[HTTPTransition]] {
var links = [String:[HTTPTransition]]()

for (relation, options) in halLinks {
if let options = options as? [String:AnyObject],
href = options["href"] as? String
{
let transition = HTTPTransition(uri: href)
let transition = HTTPTransition(uri: href, { (builder) in
parseHALLinkAttributes(options, builder: builder)
})
links[relation] = [transition]
} else if let options = options as? [[String:AnyObject]] {
links[relation] = options.flatMap {
let transitionOptions = $0
if let href = $0["href"] as? String {
return HTTPTransition(uri: href)
let transition = HTTPTransition(uri: href, { (builder) in
parseHALLinkAttributes(transitionOptions, builder: builder)
})
return transition
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion Sources/HTTPSirenAdapter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ private func sirenActionToTransition(action:[String: AnyObject]) -> (name:String
}

if let fields = action["fields"] as? [[String:AnyObject]] {
fields.forEach(sirenFieldToAttribute(builder))
fields.forEach({ sirenFieldToAttribute(builder)(field: $0) })
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/HTTPTransitionBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class HTTPTransitionBuilder : TransitionBuilderType {
var parameters = InputProperties()

/// The suggested contentType that should be used to make the request
public var method = "POST"
public var method = "GET"
/// The suggested contentType that should be used to make the request
public var suggestedContentTypes = [String]()

Expand Down
31 changes: 31 additions & 0 deletions Tests/Adapters/HALAdapterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,35 @@ class HALAdapterTests: XCTestCase {
]
])
}

func testValidLinkAttributes() {
let linkFixture = JSONFixture("link-objects.hal", forObject: self)
let representor = deserializeHAL(linkFixture) as Representor<HTTPTransition>

guard let findTransition = representor.transitions["find"]?.first else {
XCTFail("Expected 'find' transition.")
return
}
XCTAssertNotNil(findTransition.attributes["templated"]?.value as? Bool)
XCTAssertNotNil(findTransition.attributes["type"]?.value as? String)
XCTAssertNotNil(findTransition.attributes["name"]?.value as? String)
XCTAssertNotNil(findTransition.attributes["title"]?.value as? String)
XCTAssertNotNil(findTransition.attributes["hreflang"]?.value as? String)

XCTAssertEqual(representor.transitions["admin"]?.count, 2)
for adminTransition in representor.transitions["admin"]! {
XCTAssertNotNil(adminTransition.attributes["deprecation"])
}
}

func testInvalidLinkAttribute() {
let linkFixture = JSONFixture("link-objects.hal", forObject: self)
let representor = deserializeHAL(linkFixture) as Representor<HTTPTransition>

guard let testTransition = representor.transitions["test"]?.first else {
XCTFail("Expected 'test' transition.")
return
}
XCTAssertNil(testTransition.attributes["invalid-attribute"])
}
}
50 changes: 50 additions & 0 deletions Tests/Fixtures/link-objects.hal.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"_links": {
"self": { "href": "/orders" },
"next": { "href": "/orders?page=2" },
"find": {
"href": "/orders{?id}",
"templated": true,
"type": "application/json+hal",
"name": "orders",
"title": "Find orders",
"hreflang": "en"
},
"admin": [{
"href": "/admins/2",
"title": "Fred",
"deprecation": "http://example.com/deprecation?property=admin"
}, {
"href": "/admins/5",
"title": "Kate",
"deprecation": "http://example.com/deprecation?property=admin"
}],
"test": {
"href": "/test",
"invalid-attribute": "ignored"
}
},
"currentlyProcessing": 14,
"shippedToday": 20,
"_embedded": {
"order": [{
"_links": {
"self": { "href": "/orders/123" },
"basket": { "href": "/baskets/98712" },
"customer": { "href": "/customers/7809" }
},
"total": 30.00,
"currency": "USD",
"status": "shipped"
}, {
"_links": {
"self": { "href": "/orders/124" },
"basket": { "href": "/baskets/97213" },
"customer": { "href": "/customers/12369" }
},
"total": 20.00,
"currency": "USD",
"status": "processing"
}]
}
}