Request code fixes
This commit is contained in:
parent
f5aa7823cc
commit
3eebb24a4c
@ -4,7 +4,6 @@ extension JSONEncoder {
|
|||||||
static let devRant: JSONEncoder = {
|
static let devRant: JSONEncoder = {
|
||||||
let encoder = JSONEncoder()
|
let encoder = JSONEncoder()
|
||||||
encoder.dateEncodingStrategy = .iso8601
|
encoder.dateEncodingStrategy = .iso8601
|
||||||
encoder.keyEncodingStrategy = .convertToSnakeCase
|
|
||||||
return encoder
|
return encoder
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
@ -13,7 +12,6 @@ extension JSONDecoder {
|
|||||||
static let devRant: JSONDecoder = {
|
static let devRant: JSONDecoder = {
|
||||||
let decoder = JSONDecoder()
|
let decoder = JSONDecoder()
|
||||||
decoder.dateDecodingStrategy = .iso8601WithOptionalFractionalSeconds
|
decoder.dateDecodingStrategy = .iso8601WithOptionalFractionalSeconds
|
||||||
decoder.keyDecodingStrategy = .convertFromSnakeCase
|
|
||||||
return decoder
|
return decoder
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ public struct Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func makeURLRequest(config: Config, body: Data?) -> URLRequest {
|
private func makeURLRequest(config: Config, body: Data?) -> URLRequest {
|
||||||
let urlQuery = urlEncodedQueryString(from: config.urlParameters)
|
let urlQuery = Self.urlEncodedQueryString(from: config.urlParameters)
|
||||||
guard let url = URL(string: config.backend.baseURL + config.path + urlQuery) else {
|
guard let url = URL(string: config.backend.baseURL + config.path + urlQuery) else {
|
||||||
fatalError("Couldn't create a URL")
|
fatalError("Couldn't create a URL")
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ public struct Request {
|
|||||||
return urlRequest
|
return urlRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
private func urlEncodedQueryString(from query: [String: String]) -> String {
|
public static func urlEncodedQueryString(from query: [String: String]) -> String {
|
||||||
guard !query.isEmpty else { return "" }
|
guard !query.isEmpty else { return "" }
|
||||||
var components = URLComponents()
|
var components = URLComponents()
|
||||||
components.queryItems = query.map { URLQueryItem(name: $0.key, value: $0.value) }
|
components.queryItems = query.map { URLQueryItem(name: $0.key, value: $0.value) }
|
||||||
@ -74,16 +74,24 @@ public struct Request {
|
|||||||
return plusCorrection
|
return plusCorrection
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult private func requestData<ApiError: Decodable>(urlRequest: URLRequest, apiError: ApiError.Type = EmptyError.self) async throws(Error<ApiError>) -> (data: Data, headers: [AnyHashable: Any]) {
|
@discardableResult private func requestData<ApiError: Decodable & Sendable>(urlRequest: URLRequest, apiError: ApiError.Type = EmptyError.self) async throws -> (data: Data, headers: [AnyHashable: Any]) {
|
||||||
|
let response: (Data, URLResponse)
|
||||||
do {
|
do {
|
||||||
let response = try await session.data(for: urlRequest)
|
response = try await session.data(for: urlRequest)
|
||||||
|
} catch {
|
||||||
|
if let error = error as? URLError, error.code == .notConnectedToInternet {
|
||||||
|
throw Error<ApiError>.noInternet
|
||||||
|
} else {
|
||||||
|
throw Error<ApiError>.generalError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let httpResponse = response.1 as? HTTPURLResponse {
|
if let httpResponse = response.1 as? HTTPURLResponse {
|
||||||
let data = response.0
|
let data = response.0
|
||||||
|
|
||||||
if let logger {
|
if let logger {
|
||||||
let logInputString = urlRequest.httpBody.flatMap { jsonString(data: $0, prettyPrinted: true) } ?? "(none)"
|
let logInputString = urlRequest.httpBody.flatMap { Self.jsonString(data: $0, prettyPrinted: true) } ?? "(none)"
|
||||||
let logOutputString = !data.isEmpty ? jsonString(data: data, prettyPrinted: true) ?? "-" : "(none)"
|
let logOutputString = !data.isEmpty ? Self.jsonString(data: data, prettyPrinted: true) ?? "-" : "(none)"
|
||||||
logger.log("\(urlRequest.httpMethod?.uppercased() ?? "?") \(urlRequest.url?.absoluteString ?? "")\nbody: \(logInputString)\nresponse: \(logOutputString)")
|
logger.log("\(urlRequest.httpMethod?.uppercased() ?? "?") \(urlRequest.url?.absoluteString ?? "")\nbody: \(logInputString)\nresponse: \(logOutputString)")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,17 +105,10 @@ public struct Request {
|
|||||||
} else {
|
} else {
|
||||||
throw Error<ApiError>.notHttpResponse
|
throw Error<ApiError>.notHttpResponse
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
if let error = error as? URLError, error.code == .notConnectedToInternet {
|
|
||||||
throw Error<ApiError>.noInternet
|
|
||||||
} else {
|
|
||||||
throw Error<ApiError>.generalError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// JSON Data to String converter for printing/logging purposes
|
/// JSON Data to String converter for printing/logging purposes
|
||||||
private func jsonString(data: Data, prettyPrinted: Bool) -> String? {
|
public static func jsonString(data: Data, prettyPrinted: Bool) -> String? {
|
||||||
do {
|
do {
|
||||||
let writingOptions: JSONSerialization.WritingOptions = prettyPrinted ? [.prettyPrinted] : []
|
let writingOptions: JSONSerialization.WritingOptions = prettyPrinted ? [.prettyPrinted] : []
|
||||||
let decoded: Data?
|
let decoded: Data?
|
||||||
@ -124,14 +125,13 @@ public struct Request {
|
|||||||
}
|
}
|
||||||
return decoded.flatMap { String(data: $0, encoding: .utf8) }
|
return decoded.flatMap { String(data: $0, encoding: .utf8) }
|
||||||
} catch {
|
} catch {
|
||||||
print(error)
|
|
||||||
return String(data: data, encoding: .utf8)
|
return String(data: data, encoding: .utf8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: public
|
// MARK: public
|
||||||
|
|
||||||
public func requestJson<ApiError: Decodable>(config: Config, apiError: ApiError.Type = EmptyError.self) async throws(Error<ApiError>) {
|
public func requestJson<ApiError: Decodable & Sendable>(config: Config, apiError: ApiError.Type = EmptyError.self) async throws {
|
||||||
let urlRequest = makeURLRequest(config: config, body: nil)
|
let urlRequest = makeURLRequest(config: config, body: nil)
|
||||||
try await requestData(urlRequest: urlRequest, apiError: apiError)
|
try await requestData(urlRequest: urlRequest, apiError: apiError)
|
||||||
}
|
}
|
||||||
@ -154,4 +154,11 @@ public struct Request {
|
|||||||
let outData = try await requestData(urlRequest: urlRequest, apiError: apiError).data
|
let outData = try await requestData(urlRequest: urlRequest, apiError: apiError).data
|
||||||
return try decoder.decode(Out.self, from: outData)
|
return try decoder.decode(Out.self, from: outData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func requestJson<Out: Decodable, ApiError: Decodable & Sendable>(config: Config, string: String, apiError: ApiError.Type = EmptyError.self) async throws -> Out {
|
||||||
|
let inData = string.data(using: .utf8)
|
||||||
|
let urlRequest = makeURLRequest(config: config, body: inData)
|
||||||
|
let outData = try await requestData(urlRequest: urlRequest, apiError: apiError).data
|
||||||
|
return try decoder.decode(Out.self, from: outData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
public struct SwiftDevRant {
|
public struct SwiftDevRant {
|
||||||
let request = Request(encoder: .devRant, decoder: .devRant)
|
let request: Request
|
||||||
let backend = DevRantBackend()
|
let backend = DevRantBackend()
|
||||||
|
|
||||||
|
public init(requestLogger: Logger) {
|
||||||
|
self.request = Request(encoder: .devRant, decoder: .devRant, logger: requestLogger)
|
||||||
|
}
|
||||||
|
|
||||||
func makeConfig(_ method: Request.Method, path: String, urlParameters: [String: String] = [:], headers: [String: String] = [:], token: AuthToken? = nil) -> Request.Config {
|
func makeConfig(_ method: Request.Method, path: String, urlParameters: [String: String] = [:], headers: [String: String] = [:], token: AuthToken? = nil) -> Request.Config {
|
||||||
var urlParameters = urlParameters
|
var urlParameters = urlParameters
|
||||||
urlParameters["app"] = "3"
|
urlParameters["app"] = "3"
|
||||||
@ -19,12 +23,16 @@ public struct SwiftDevRant {
|
|||||||
|
|
||||||
public func logIn(username: String, password: String) async throws -> AuthToken {
|
public func logIn(username: String, password: String) async throws -> AuthToken {
|
||||||
var parameters: [String: String] = [:]
|
var parameters: [String: String] = [:]
|
||||||
|
parameters["app"] = "3"
|
||||||
parameters["username"] = username
|
parameters["username"] = username
|
||||||
parameters["password"] = password
|
parameters["password"] = password
|
||||||
|
|
||||||
let config = makeConfig(.post, path: "users/auth-token", urlParameters: parameters)
|
let config = makeConfig(.post, path: "users/auth-token")
|
||||||
|
|
||||||
let response: AuthToken.CodingData.Container = try await request.requestJson(config: config, apiError: DevRantApiError.CodingData.self)
|
// For the log in request the url encoded parameters are passed as a string in the http body instead of in the URL.
|
||||||
|
let body = String(Request.urlEncodedQueryString(from: parameters).dropFirst()) // dropping the first character "?"
|
||||||
|
|
||||||
|
let response: AuthToken.CodingData.Container = try await request.requestJson(config: config, string: body, apiError: DevRantApiError.CodingData.self)
|
||||||
|
|
||||||
return response.auth_token.decoded
|
return response.auth_token.decoded
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user