LeadKit/TIMoyaNetworking/README.md

198 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TIMoyaNetworking
Moya + Swagger network service.
## Example of network service on project
Models:
```swift
enum ErrorType: String, Codable {
// 400
case incorrectLoginAndPasswordGiven = "Incorrect login and password given"
// 401
case invalidJwtToken = "Invalid JWT Token"
// 403
case userAlreadyExists = "User already exists"
// 404
case userNotFound = "User not found"
case sessionNotFound = "Session not found"
// 500
case internalError = "Internal error"
// 503
case cannotSendCode = "Cannot send code"
// Unknown
case unknown = "Unknown error"
init(_ rawValue: String, `default`: ErrorType = .unknown) {
self = ErrorType(rawValue: rawValue) ?? `default`
}
}
struct ErrorResponse: Codable {
let errorCode: ErrorType
let message: String
}
struct LoginRequestBody: Encodable {
var login: String
var password: String
}
struct Profile: Codable {
var name: String
}
enum ApiResponse<ResponseType> {
case ok(ResponseType)
case error(ErrorResponse)
}
```
Codable model:
```swift
struct Token: Codable {
private enum CodingKeys: String, CodingKey {
case name
case value
case expirationDate = "expiration"
}
var name: String
var value: String
var expirationDate: Date
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
value = try container.decode(String.self, forKey: .value)
let dateFormatter = try decoder.userInfo.dateFormatter(for: APIDateFormat.yyyyMMddTHHmmssSZ)
expirationDate = try container.decodeDate(forKey: .expirationDate,
using: dateFormatter)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(value, forKey: .value)
let dateFormatter = try encoder.userInfo.dateFormatter(for: APIDateFormat.yyyyMMddTHHmmssSZ)
try container.encode(date: expirationDate,
forKey: .expirationDate,
using: dateFormatter)
}
}
```
Request:
```swift
extension EndpointRequest {
static func apiV3MobileAuthLoginPassword(body: LoginRequestBody) -> EndpointRequest<LoginRequestBody> {
.init(templatePath: "/api/v3/mobile/auth/login/password/",
method: .post,
body: body,
acceptableStatusCodes: [200, 400, 403, 500],
server: Server(baseUrl: "https://server.base.url"))
}
}
```
JSON coders helper:
```swift
struct JsonCodingService {
let jsonEncoder: JSONEncoder
let jsonDecoder: JSONDecoder
init(dateFormattersReusePool: DateFormattersReusePool) {
self.jsonEncoder = JSONEncoder()
self.jsonDecoder = JSONDecoder()
guard let userInfoKey = CodingUserInfoKey.dateFormattersReusePool else {
assertionFailure("Unable to create dateFormattersReusePool CodingUserInfoKey")
return
}
jsonDecoder.userInfo.updateValue(dateFormattersReusePool, forKey: userInfoKey)
jsonEncoder.userInfo.updateValue(dateFormattersReusePool, forKey: userInfoKey)
}
}
```
Main network service:
```swift
final class ProjectNetworkService: DefaultJsonNetworkService {
init(jsonCodingService: JsonCodingService) {
super.init(session: SessionFactory(timeoutInterval: 60).createSession(),
jsonDecoder: jsonCodingService.jsonDecoder,
jsonEncoder: jsonCodingService.jsonEncoder)
}
func process<B: Encodable, S: Decodable>(request: EndpointRequest<B>,
decodableSuccessStatusCodes: Set<Int>? = nil,
decodableFailureStatusCodes: Set<Int>? = nil) async -> ApiResponse<S> {
await process(request: request,
decodableSuccessStatusCodes: decodableSuccessStatusCodes,
decodableFailureStatusCodes: decodableFailureStatusCodes,
mapSuccess: ApiResponse.ok,
mapFailure: ApiResponse.error,
mapMoyaError: { ApiResponse.error($0.convertToErrorModel()) })
}
}
private extension MoyaError {
func convertToErrorModel() -> ErrorResponse {
switch self {
case .underlying:
return ErrorResponse(errorCode: .unknown,
message: "Нет соединения с сетью 😔 Проверьте соединение с сетью и повторите попытку")
case .objectMapping:
return ErrorResponse(errorCode: .unknown,
message: "Ошибка 😔")
default:
return ErrorResponse(errorCode: .unknown,
message: "Ошибка 😔")
}
}
}
```
## Example of usage
```swift
let reusePool = DateFormattersReusePool()
let jsonCodingService = JsonCodingService(dateFormattersReusePool: reusePool)
let networkSerice = ProjectNetworkService(jsonCodingService: jsonCodingService)
let body = LoginRequestBody(login: "qwe", password: "asd")
let profile: ApiResponse<Profile> = await networkSerice.process(request: .apiV3MobileAuthLoginPassword(body: body))
switch profileResponse {
case let .ok(profile):
showUser(name: profile.name)
case let .error(errorResponse):
showAlert(with: errorResponse.message)
}
```