Skip to content

Repository files navigation

NetworkKit

Swift iOS SPM

Swift 6과 async/await 기반의 iOS 네트워크 라이브러리입니다.

HTTP 요청, Error 처리, Retry, Interceptor, Response Validation, Multipart Upload, Download를 한 흐름으로 다루기 위해 만들었습니다.

목차

왜 만들었는가

실무에서 반복적으로 다음 문제를 경험했습니다.

  • URLSession 코드가 프로젝트마다 달라짐
  • Error 처리 방식이 통일되지 않음
  • Header 추가가 중복됨
  • Retry 구현이 프로젝트마다 다름
  • 로그 출력 방식이 제각각

이 문제를 해결하기 위해 NetworkKit을 만들었습니다.

NetworkKit은 네트워크 레이어의 책임을 Endpoint, Client, Session, Interceptor, ResponseValidator, Monitor, Logger로 나누어 요청 정의와 실행 흐름을 분리합니다.

핵심 기능

기능 설명
async/await request URLSession 기반 비동기 요청을 실행합니다.
Endpoint 추상화 base URL, path, method, headers, parameters, encoder를 한 타입에 모읍니다.
Response Validation Endpoint별 성공 status code와 content type 조건을 검증합니다.
Interceptor 요청 전 adapt, 실패 후 retry를 처리합니다.
RetryPolicy max attempts와 seconds 기반 backoff를 설정합니다.
Multipart Upload 단일 UploadData 기반 multipart/form-data upload를 지원합니다.
Download 파일을 메모리에 올리지 않고 지정 위치로 저장합니다.
Testable Session API.Session protocol로 URLSession을 mock할 수 있게 했습니다.

Architecture

요청 흐름은 다음과 같습니다.

Endpoint
  -> Client.request
  -> Monitor
  -> endpoint.asURLRequest()
  -> Interceptor.adapt
  -> Session.data(for:)
  -> ResponseValidator.validate
  -> JSONDecoder.decode
  -> Decodable Model

업로드 흐름은 다음과 같습니다.

Endpoint.uploadData
  -> multipart body 생성
  -> Content-Type boundary 설정
  -> Session.upload(for:from:)
  -> ResponseValidator.validate
  -> JSONDecoder.decode

다운로드 흐름은 다음과 같습니다.

Endpoint
  -> Session.download(for:)
  -> ResponseValidator.validate
  -> temporary file 이동
  -> DownloadResponse

Retry는 session/transport error 또는 HTTP status validation failure 발생 후 Interceptor가 결정합니다.

Session 실패 또는 retry 가능한 status code 실패
  -> Interceptor.retry(...)
     +-- .retry -> backoff -> newRequest로 재시도
     +-- .doNotRetry(error) -> Error 반환

상세 설명은 Architecture 문서에서 확인할 수 있습니다.

설치

Swift Package Manager로 추가합니다.

dependencies: [
    .package(url: "https://github.com/HenryVoid/Network.git", branch: "main")
]
targets: [
    .target(
        name: "YourTarget",
        dependencies: [
            .product(name: "NetworkKit", package: "Network")
        ]
    )
]

Xcode에서는 File > Add Package Dependencies...에서 https://github.com/HenryVoid/Network.git를 추가하고 NetworkKit product를 선택합니다.

Repository 이름은 Network, package/product 이름은 NetworkKit입니다.

빠른 사용 예시

Endpoint를 정의하고 Client에서 호출합니다.

import Foundation
import NetworkKit

struct UserResponse: Decodable {
    let id: Int
    let name: String
}

struct UserEndpoint: API.Endpoint {
    let baseURL: any API.URLConvertible = "https://api.example.com"
    let path: String? = "users/1"
    let method: API.HTTPMethod = .get
    let headers: API.HttpHeaders? = [
        .init(key: "Accept", value: "application/json")
    ]
    let parameters: API.Parameters? = nil
    let encoder: any API.ParameterEncodable = API.URLParameterEncoder()
}

let client = API.Client(
    session: URLSession.shared,
    interceptors: [],
    retryPolicy: .default
)

let user = try await client.request(
    UserEndpoint(),
    decode: UserResponse.self
)

requestasync throws(API.Error)로 동작합니다. 성공하면 Decodable 모델을 반환합니다.

Endpoint별 성공 조건이 다르면 validator를 재정의합니다.

struct CreateUserEndpoint: API.Endpoint {
    let baseURL: any API.URLConvertible = "https://api.example.com"
    let path: String? = "users"
    let method: API.HTTPMethod = .post
    let headers: API.HttpHeaders? = [
        .init(key: "Accept", value: "application/json")
    ]
    let parameters: API.Parameters? = ["name": "Henry"]
    let encoder: any API.ParameterEncodable = API.JSONParameterEncoder()
    let validator = API.ResponseValidator(
        acceptableStatusCodes: 201..<202,
        acceptableContentTypes: ["application/json"]
    )
}

기능별 문서

문서 내용
Architecture 전체 요청 흐름과 책임 분리
Client request/upload/download 실행 흐름
Endpoint 요청 정의 방식
Session URLSession 추상화와 테스트 주입
Response Validation status code, content type 검증
Retry RetryPolicyInterceptor.retry
Interceptor request adapt와 retry 확장 지점
Multipart Upload 단일 파일 multipart upload
Download 파일 download와 destination 이동
Monitor actor 기반 네트워크 상태 확인
Logger masking, body limit, output injection
Error Handling API.Error 계층
Encoding JSON/URL parameter encoding
HTTP Header header 모델과 request 적용
URLConvertible URL 변환 추상화
Testing Mock 기반 테스트 전략

주요 타입

타입 역할
API.Client request/upload/download 실행
API.Endpoint 요청 정의
API.Session 세션 추상화
API.Interceptor request adapt, retry 결정
API.ResponseValidator response 검증
API.RetryPolicy retry 횟수와 backoff 계산
API.DownloadDestination download 저장 위치와 overwrite 정책
API.DownloadResponse 저장된 file URL과 response metadata
API.Monitorable 연결 상태 확인
API.Loggable logging 추상화
API.Error typed error 모델

Test

Swift Testing으로 실패 상황과 요청 생성 흐름을 검증했습니다.

실패 테스트는 API.Error의 구체 case를 pattern matching으로 확인합니다.

테스트 대상 검증 내용
Client Request invalid URL, connection failure, session failure, decode failure, invalid status code, invalid URLResponse
Client Response Validation custom status code success/failure, content type failure
Client Retry session retry, HTTP status retry, retry exceeded, doNotRetry, cancellation
Client Upload upload success, missing uploadData failure, upload failure
Client Download download success, validation failure, existing file failure, overwrite success, retry success, HTTP status retry, cancellation
Endpoint JSON parameter request, URL parameter request, default response validator
ResponseValidator default/custom status code, content type match/mismatch, invalid URLResponse
HTTP Header dictionary 변환, string 변환, URLRequest header 추가
Interceptor adapt로 header 추가
JSON/URL Encoder JSON body encoding, URL query item encoding
Logger 민감 header masking, body 길이 제한, logging 비활성화
Monitor API.Monitor.shared 연결 상태 확인, status timeout
RetryPolicy delay 계산, maxAttempts 최소값 보정
URLConvertible String to URL 변환, invalid URL failure

테스트 파일 일부는 #if !os(macOS) 조건 안에 있어 iOS 테스트 환경을 기준으로 실행됩니다.

Roadmap

항목 설명
Download progress/resume progress, pause/resume, background download를 분리해 확장합니다.
Retry-After/Jitter Retry-After header와 jitter 기반 backoff를 분리해 확장합니다.
Multipart form field 단일 파일 외 일반 form field와 여러 파일 업로드를 지원합니다.
Metrics 요청 시간, payload 크기, retry 횟수 같은 측정값을 노출합니다.

Requirements

항목
Swift tools version 5.9
Swift language version 6
Platform iOS 17+
Package manager Swift Package Manager
Dependencies 없음

About

Swift 6 networking library with async/await, interceptors, retry, multipart upload, and Swift Testing

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages