Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make UploadFile type codable. #289

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
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
14 changes: 14 additions & 0 deletions Specs/BinaryUpload/generated/Swift/BinaryUpload.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Pod::Spec.new do |s|
s.source_files = '*.swift'
s.name = 'BinaryUpload'
s.authors = 'Yonas Kolb'
s.summary = 'A generated API'
s.version = '1.0'
s.homepage = 'https://github.com/yonaskolb/SwagGen'
s.source = { :git => 'git@github.com:https://github.com/yonaskolb/SwagGen.git' }
s.ios.deployment_target = '10.0'
s.tvos.deployment_target = '10.0'
s.osx.deployment_target = '10.12'
s.source_files = 'Sources/**/*.swift'
s.dependency 'Alamofire', '~> 5.4.4'
end
2 changes: 2 additions & 0 deletions Specs/BinaryUpload/generated/Swift/Cartfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

github "Alamofire/Alamofire" ~> 5.4.4
24 changes: 24 additions & 0 deletions Specs/BinaryUpload/generated/Swift/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
24 changes: 24 additions & 0 deletions Specs/BinaryUpload/generated/Swift/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// swift-tools-version:5.2

import PackageDescription

let package = Package(
name: "BinaryUpload",
platforms: [
.macOS(.v10_12),
.iOS(.v10),
.tvOS(.v10),
.watchOS(.v3)
],
products: [
.library(name: "BinaryUpload", targets: ["BinaryUpload"])
],
dependencies: [
.package(url: "https://github.com/Alamofire/Alamofire.git", .exact("5.4.4")),
],
targets: [
.target(name: "BinaryUpload", dependencies: [
"Alamofire",
], path: "Sources")
]
)
158 changes: 158 additions & 0 deletions Specs/BinaryUpload/generated/Swift/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# BinaryUpload

This is an api generated from a OpenAPI 3.0 spec with [SwagGen](https://github.com/yonaskolb/SwagGen)

## Operation

Each operation lives under the `BinaryUpload` namespace and within an optional tag: `BinaryUpload(.tagName).operationId`. If an operation doesn't have an operationId one will be generated from the path and method.

Each operation has a nested `Request` and a `Response`, as well as a static `service` property

#### Service

This is the struct that contains the static information about an operation including it's id, tag, method, pre-modified path, and authorization requirements. It has a generic `ResponseType` type which maps to the `Response` type.
You shouldn't really need to interact with this service type.

#### Request

Each request is a subclass of `APIRequest` and has an `init` with a body param if it has a body, and a `options` struct for other url and path parameters. There is also a convenience init for passing parameters directly.
The `options` and `body` structs are both mutable so they can be modified before actually sending the request.

#### Response

The response is an enum of all the possible responses the request can return. it also contains getters for the `statusCode`, whether it was `successful`, and the actual decoded optional `success` response. If the operation only has one type of failure type there is also an optional `failure` type.

## Model
Models that are sent and returned from the API are mutable classes. Each model is `Equatable` and `Codable`.

`Required` properties are non optional and non-required are optional

All properties can be passed into the initializer, with `required` properties being mandatory.

If a model has `additionalProperties` it will have a subscript to access these by string

## APIClient
The `APIClient` is used to encode, authorize, send, monitor, and decode the requests. There is a `APIClient.default` that uses the default `baseURL` otherwise a custom one can be initialized:

```swift
public init(baseURL: String, sessionManager: SessionManager = .default, defaultHeaders: [String: String] = [:], behaviours: [RequestBehaviour] = [])
```

#### APIClient properties

- `baseURL`: The base url that every request `path` will be appended to
- `behaviours`: A list of [Request Behaviours](#requestbehaviour) to add to every request
- `sessionManager`: An `Alamofire.SessionManager` that can be customized
- `defaultHeaders`: Headers that will be applied to every request
- `decodingQueue`: The `DispatchQueue` to decode responses on

#### Making a request
To make a request first initialize a [Request](#request) and then pass it to `makeRequest`. The `complete` closure will be called with an `APIResponse`

```swift
func makeRequest<T>(_ request: APIRequest<T>, behaviours: [RequestBehaviour] = [], queue: DispatchQueue = DispatchQueue.main, complete: @escaping (APIResponse<T>) -> Void) -> Request? {
```

Example request (that is not neccessarily in this api):

```swift

let getUserRequest = BinaryUpload.User.GetUser.Request(id: 123)
let apiClient = APIClient.default

apiClient.makeRequest(getUserRequest) { apiResponse in
switch apiResponse {
case .result(let apiResponseValue):
if let user = apiResponseValue.success {
print("GetUser returned user \(user)")
} else {
print("GetUser returned \(apiResponseValue)")
}
case .error(let apiError):
print("GetUser failed with \(apiError)")
}
}
```

Each [Request](#request) also has a `makeRequest` convenience function that uses `BinaryUpload.shared`.

#### APIResponse
The `APIResponse` that gets passed to the completion closure contains the following properties:

- `request`: The original request
- `result`: A `Result` type either containing an `APIClientError` or the [Response](#response) of the request
- `urlRequest`: The `URLRequest` used to send the request
- `urlResponse`: The `HTTPURLResponse` that was returned by the request
- `data`: The `Data` returned by the request.
- `timeline`: The `Alamofire.Timeline` of the request which contains timing information.

#### Encoding and Decoding
Only JSON requests and responses are supported. These are encoded and decoded by `JSONEncoder` and `JSONDecoder` respectively, using Swift's `Codable` apis.
There are some options to control how invalid JSON is handled when decoding and these are available as static properties on `BinaryUpload`:

- `safeOptionalDecoding`: Whether to discard any errors when decoding optional properties. Defaults to `true`.
- `safeArrayDecoding`: Whether to remove invalid elements instead of throwing when decoding arrays. Defaults to `true`.

Dates are encoded and decoded differently according to the swagger date format. They use different `DateFormatter`'s that you can set.
- `date-time`
- `DateTime.dateEncodingFormatter`: defaults to `yyyy-MM-dd'T'HH:mm:ss.Z`
- `DateTime.dateDecodingFormatters`: an array of date formatters. The first one to decode successfully will be used
- `date`
- `DateDay.dateFormatter`: defaults to `yyyy-MM-dd`

#### APIClientError
This is error enum that `APIResponse.result` may contain:

```swift
public enum APIClientError: Error {
case unexpectedStatusCode(statusCode: Int, data: Data)
case decodingError(DecodingError)
case requestEncodingError(String)
case validationError(String)
case networkError(Error)
case unknownError(Error)
}
```

#### RequestBehaviour
Request behaviours are used to modify, authorize, monitor or respond to requests. They can be added to the `APIClient.behaviours` for all requests, or they can passed into `makeRequest` for just that single request.

`RequestBehaviour` is a protocol you can conform to with each function being optional. As the behaviours must work across multiple different request types, they only have access to a typed erased `AnyRequest`.

```swift
public protocol RequestBehaviour {

/// runs first and allows the requests to be modified. If modifying asynchronously use validate
func modifyRequest(request: AnyRequest, urlRequest: URLRequest) -> URLRequest

/// validates and modifies the request. complete must be called with either .success or .fail
func validate(request: AnyRequest, urlRequest: URLRequest, complete: @escaping (RequestValidationResult) -> Void)

/// called before request is sent
func beforeSend(request: AnyRequest)

/// called when request successfuly returns a 200 range response
func onSuccess(request: AnyRequest, result: Any)

/// called when request fails with an error. This will not be called if the request returns a known response even if the a status code is out of the 200 range
func onFailure(request: AnyRequest, error: APIClientError)

/// called if the request recieves a network response. This is not called if request fails validation or encoding
func onResponse(request: AnyRequest, response: AnyResponse)
}
```

### Authorization
Each request has an optional `securityRequirement`. You can create a `RequestBehaviour` that checks this requirement and adds some form of authorization (usually via headers) in `validate` or `modifyRequest`. An alternative way is to set the `APIClient.defaultHeaders` which applies to all requests.

#### Reactive and Promises
To add support for a specific asynchronous library, just add an extension on `APIClient` and add a function that wraps the `makeRequest` function and converts from a closure based syntax to returning the object of choice (stream, future...ect)

## Models

- **UploadModel**

## Requests

- **BinaryUpload.PostUser**: POST `/withoutmodel`
- **BinaryUpload.PostWithType**: POST `/withmodel`
28 changes: 28 additions & 0 deletions Specs/BinaryUpload/generated/Swift/Sources/API.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Generated by SwagGen
// https://github.com/yonaskolb/SwagGen
//

import Foundation

public struct BinaryUpload {

/// Whether to discard any errors when decoding optional properties
public static var safeOptionalDecoding = false

/// Whether to remove invalid elements instead of throwing when decoding arrays
public static var safeArrayDecoding = false

/// Used to encode Dates when uses as string params
public static var dateEncodingFormatter = DateFormatter(formatString: "yyyy-MM-dd'T'HH:mm:ssZZZZZ",
locale: Locale(identifier: "en_US_POSIX"),
calendar: Calendar(identifier: .gregorian))

public static let version = "1.0"


public enum Server {

public static let main = "http://localhost:3000"
}
}
Loading