Skip to content

Commit

Permalink
Reworked error handling and removed throws declaration from REST func…
Browse files Browse the repository at this point in the history
…tions. Added subscript methods for structs using dictionaries.
  • Loading branch information
joerghartmann committed Nov 9, 2022
1 parent 2abb592 commit 9f6efe6
Show file tree
Hide file tree
Showing 64 changed files with 2,105 additions and 2,706 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,21 @@ The `URLSession` may also be passed to individual `API` classes through it's ini
let api = ApplicationsApi(session: session)
```

### Use your own domain model

The CumulocityCoreLibrary allows custom data models. The following classes are designed to be extendible:

- `C8yAlarm`, `C8yAuditRecord`, `C8yCategoryOptions`, `C8yCustomProperties`, `C8yEvent`, `C8yManagedObject`, `C8yMeasurement`, `C8yOperation`

Those classes allow to add an arbitrary number of additional properties as a list of key-value pairs. These properties are known as custom fragments and can be of any type. Each custom fragment is identified by a unique name. Thus, developers can propagate their custom fragments using:

```swift
C8yAlarm.registerAdditionalProperty<C: Codable>(typeName: String, for type: C.Type)
```

Each of the extensible objects contains a dictionary object holding instances of custom fragments. Use the custom fragment's key to access it's value.

In addition, developers may create subclasses. The client implementation respects subclassing by using generic type arguments.
### Working with errors

Use `sink(receiveCompletion:receiveValue:)` to observe values received by the publisher and process them using a closure you specify. HTTP error codes will be forwarded and can be accessed using a completion handler. The client describes two error types:
Expand Down
144 changes: 50 additions & 94 deletions Sources/CumulocityCoreLibrary/Api/AlarmsApi.swift

Large diffs are not rendered by default.

58 changes: 17 additions & 41 deletions Sources/CumulocityCoreLibrary/Api/ApplicationBinariesApi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class ApplicationBinariesApi: AdaptableApi {
/// - Parameters:
/// - id
/// Unique identifier of the application.
public func getApplicationAttachments(id: String) throws -> AnyPublisher<C8yApplicationBinaries, Swift.Error> {
public func getApplicationAttachments(id: String) -> AnyPublisher<C8yApplicationBinaries, Error> {
let builder = URLRequestBuilder()
.set(resourcePath: "/application/applications/\(id)/binaries")
.set(httpMethod: "get")
Expand All @@ -40,21 +40,12 @@ public class ApplicationBinariesApi: AdaptableApi {
guard let httpResponse = element.response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
guard httpResponse.statusCode != 401 else {
let decoder = JSONDecoder()
let error401 = try decoder.decode(C8yError.self, from: element.data)
throw Errors.badResponseError(response: httpResponse, reason: error401)
}
guard httpResponse.statusCode != 404 else {
let decoder = JSONDecoder()
let error404 = try decoder.decode(C8yError.self, from: element.data)
throw Errors.badResponseError(response: httpResponse, reason: error404)
}
// generic error fallback
guard (200..<300) ~= httpResponse.statusCode else {
if let c8yError = try? JSONDecoder().decode(C8yError.self, from: element.data) {
throw Errors.badResponseError(response: httpResponse, reason: c8yError)
}
throw Errors.undescribedError(response: httpResponse)
}

return element.data
}).decode(type: C8yApplicationBinaries.self, decoder: JSONDecoder()).eraseToAnyPublisher()
}
Expand Down Expand Up @@ -86,9 +77,9 @@ public class ApplicationBinariesApi: AdaptableApi {
/// The ZIP file to be uploaded.
/// - id
/// Unique identifier of the application.
public func uploadApplicationAttachment(file: Data, id: String) throws -> AnyPublisher<C8yApplication, Swift.Error> {
public func uploadApplicationAttachment(file: Data, id: String) -> AnyPublisher<C8yApplication, Error> {
let multipartBuilder = MultipartFormDataBuilder()
try multipartBuilder.addBodyPart(named: "file", data: file, mimeType: "application/zip");
try? multipartBuilder.addBodyPart(named: "file", data: file, mimeType: "application/zip");
let builder = URLRequestBuilder()
.set(resourcePath: "/application/applications/\(id)/binaries")
.set(httpMethod: "post")
Expand All @@ -100,16 +91,12 @@ public class ApplicationBinariesApi: AdaptableApi {
guard let httpResponse = element.response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
guard httpResponse.statusCode != 401 else {
let decoder = JSONDecoder()
let error401 = try decoder.decode(C8yError.self, from: element.data)
throw Errors.badResponseError(response: httpResponse, reason: error401)
}
// generic error fallback
guard (200..<300) ~= httpResponse.statusCode else {
if let c8yError = try? JSONDecoder().decode(C8yError.self, from: element.data) {
throw Errors.badResponseError(response: httpResponse, reason: c8yError)
}
throw Errors.undescribedError(response: httpResponse)
}

return element.data
}).decode(type: C8yApplication.self, decoder: JSONDecoder()).eraseToAnyPublisher()
}
Expand All @@ -133,7 +120,7 @@ public class ApplicationBinariesApi: AdaptableApi {
/// Unique identifier of the application.
/// - binaryId
/// Unique identifier of the binary.
public func getApplicationAttachment(id: String, binaryId: String) throws -> AnyPublisher<Data, Swift.Error> {
public func getApplicationAttachment(id: String, binaryId: String) -> AnyPublisher<Data, Error> {
let builder = URLRequestBuilder()
.set(resourcePath: "/application/applications/\(id)/binaries/\(binaryId)")
.set(httpMethod: "get")
Expand All @@ -142,16 +129,12 @@ public class ApplicationBinariesApi: AdaptableApi {
guard let httpResponse = element.response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
guard httpResponse.statusCode != 401 else {
let decoder = JSONDecoder()
let error401 = try decoder.decode(C8yError.self, from: element.data)
throw Errors.badResponseError(response: httpResponse, reason: error401)
}
// generic error fallback
guard (200..<300) ~= httpResponse.statusCode else {
if let c8yError = try? JSONDecoder().decode(C8yError.self, from: element.data) {
throw Errors.badResponseError(response: httpResponse, reason: c8yError)
}
throw Errors.undescribedError(response: httpResponse)
}

return element.data
}).eraseToAnyPublisher()
}
Expand All @@ -177,7 +160,7 @@ public class ApplicationBinariesApi: AdaptableApi {
/// Unique identifier of the application.
/// - binaryId
/// Unique identifier of the binary.
public func deleteApplicationAttachment(id: String, binaryId: String) throws -> AnyPublisher<Data, Swift.Error> {
public func deleteApplicationAttachment(id: String, binaryId: String) -> AnyPublisher<Data, Error> {
let builder = URLRequestBuilder()
.set(resourcePath: "/application/applications/\(id)/binaries/\(binaryId)")
.set(httpMethod: "delete")
Expand All @@ -186,19 +169,12 @@ public class ApplicationBinariesApi: AdaptableApi {
guard let httpResponse = element.response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
guard httpResponse.statusCode != 401 else {
let decoder = JSONDecoder()
let error401 = try decoder.decode(C8yError.self, from: element.data)
throw Errors.badResponseError(response: httpResponse, reason: error401)
}
guard httpResponse.statusCode != 403 else {
throw Errors.badResponseError(response: httpResponse, reason: "Not authorized to perform this operation.")
}
// generic error fallback
guard (200..<300) ~= httpResponse.statusCode else {
if let c8yError = try? JSONDecoder().decode(C8yError.self, from: element.data) {
throw Errors.badResponseError(response: httpResponse, reason: c8yError)
}
throw Errors.undescribedError(response: httpResponse)
}

return element.data
}).eraseToAnyPublisher()
}
Expand Down

0 comments on commit 9f6efe6

Please sign in to comment.