Skip to content
Merged
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
10 changes: 5 additions & 5 deletions Sources/Core/NXCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

import Foundation

/// 성공한 GET 응답과 진행 중인 동일 요청에 대한 응답 캐시 동작입니다.
/// 성공한 GET 응답과 진행 중인 동일 요청의 cache 동작
public enum NXCache: Sendable, Equatable {
/// 응답을 캐시하지 않고 동일한 요청을 각각 별도로 실행합니다.
/// 동일한 요청 cache 미적용, 개별 실행
case disabled
/// 지정된 TTL 동안 성공한 GET 응답을 메모리에 저장하고, 검증자 재검증 없이 진행 중인 동일 GET 요청 결과를 재사용합니다.
/// 지정된 TTL 동안 성공한 GET 응답 메모리 저장, validator 재검증 없음, 진행 동일 GET 요청 결과 재사용
case memory(ttl: TimeInterval)
/// 지정된 TTL 동안 성공한 GET 응답을 메모리에 저장하고, 만료된 검증자 기반 `200` 응답을 재검증합니다.
/// 지정된 TTL 동안 성공한 GET 응답 메모리 저장, 만료된 validator 기반 `200` 응답 재검증
///
/// 캐시는 이 정책을 받는 `NXAPIClient` 인스턴스에 속합니다. 클라이언트를 다시 생성하면 독립적인 캐시가 생깁니다.
/// cache 소유권은 정책 적용 `NXAPIClient` instance 단위, client 재생성 시 독립 cache 생성
case revalidatingMemory(ttl: TimeInterval)
}
46 changes: 23 additions & 23 deletions Sources/Core/NXClientConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

import Foundation

/// API 클라이언트가 생성하는 모든 요청에 적용되는 공통 설정입니다.
/// API client가 생성하는 모든 요청의 공통 설정
///
/// ## 개요
///
/// 공통 네트워킹 동작을 한 곳에 정의하고 `NXAPIClient`를 통해 재사용하세요.
/// 공통 네트워크 동작의 단일 정의 지점, `NXAPIClient` 통한 재사용
///
/// ```swift
/// import Foundation
Expand All @@ -30,40 +30,40 @@ import Foundation
/// let client = NXAPIClient(configuration: configuration)
/// ```
public struct NXClientConfiguration: Sendable {
/// 상대 경로 요청을 해석할 때 사용하는 기본 URL입니다.
/// 상대 경로 요청 해석 기본 URL
public let baseURL: URL
/// 모든 요청에 추가되는 헤더입니다. 키가 겹치면 요청 단위 헤더가 이 헤더를 덮어씁니다.
/// 모든 요청 공통 header(키 충돌 시 요청 단위 header 우선 적용)
public let headers: [String: String]
/// 조립된 `URLRequest` 실행에 사용하는 전송 계층입니다.
/// 조립된 `URLRequest` 실행 transport
public let transport: any NXHTTPTransport
/// 요청 라이프사이클 이벤트를 수신하는 로거입니다.
/// 요청 lifecycle event 수신 logger
public let logger: any NXLogger
/// 모든 요청에 적용되는 인터셉터입니다.
/// 요청별 적용 interceptor
public let interceptors: [any NXHTTPInterceptor]
/// 성공한 GET 응답과 진행 중인 동일 요청에 대한 캐시 동작입니다.
/// 성공한 GET 응답 및 진행 동일 요청의 cache 동작
public let cache: NXCache
/// 타입 지정 요청에서 응답 본문을 디코딩할 때 사용하는 디코더입니다.
/// type 지정 요청 응답 body decoder
public let decoder: JSONDecoder
/// `json(_:encoder:)`에 인코더가 전달되지 않을 때 JSON 요청 본문을 만드는 인코더입니다.
/// `json(_:encoder:)` 미전달 시 사용 JSON 요청 body encoder
public let encoder: JSONEncoder
/// 실패한 서버 응답을 도메인 전용 오류로 매핑할 수 있는 디코더입니다.
/// 실패한 서버 응답을 도메인 전용 오류로 mapping하는 decoder
public let serverErrorDecoder: any NXServerErrorDecoder
/// 인증 요청에서 베어러 토큰을 조회하고 갱신하는 데 사용하는 공급자입니다.
/// 인증 요청에서 베어러 토큰 조회 및 갱신 provider
public let authTokenProvider: (any NXAuthTokenProvider)?

/// 클라이언트 구성을 생성합니다.
/// client 구성 initialization
///
/// - Parameters:
/// - baseURL: 상대 경로 요청을 해석할 때 사용하는 기본 URL입니다.
/// - headers: 모든 요청에 추가되는 헤더입니다.
/// - transport: 요청 실행을 담당하는 전송 계층입니다.
/// - logger: 요청 라이프사이클 이벤트를 받는 로거입니다.
/// - interceptors: 모든 요청에 적용되는 인터셉터 목록입니다.
/// - cache: 성공한 GET 응답 및 진행 중인 동일 요청에 대한 캐시 동작입니다.
/// - decoder: 타입 지정 응답 디코딩에 사용하는 디코더입니다.
/// - encoder: JSON 요청 본문 인코딩에 사용하는 인코더입니다.
/// - serverErrorDecoder: 실패 응답을 커스텀 오류로 매핑하는 디코더입니다.
/// - authTokenProvider: 인증 요청에 사용되는 공급자입니다.
/// - baseURL: 상대 경로 요청 해석 기본 URL
/// - headers: 모든 요청 공통 header(키 충돌 시 요청 단위 header 우선 적용)
/// - transport: 요청 실행 transport
/// - logger: 요청 lifecycle event 수신 logger
/// - interceptors: 요청 적용 interceptor 목록
/// - cache: 성공한 GET 응답 및 진행 동일 요청의 cache 동작
/// - decoder: type 지정 응답 decoding decoder
/// - encoder: JSON 요청 body encoder
/// - serverErrorDecoder: 실패 응답 사용자 정의 오류 mapping decoder
/// - authTokenProvider: 인증 요청용 token provider
public init(
baseURL: URL,
headers: [String: String] = [:],
Expand Down
22 changes: 11 additions & 11 deletions Sources/Core/NXError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@

import Foundation

/// Nexa가 요청 조립, 전송, 유효성 검사, 디코딩 과정에서 발생시키는 오류입니다.
/// Nexa 요청 조립·transport·validation·decoding 과정 오류
public enum NXError: Error, Sendable {
/// 입력으로 유효한 HTTP 요청을 만들 수 없어 요청 조립이 실패했습니다.
/// 입력으로 유효한 HTTP 요청 생성 실패
case invalidRequest(String)
/// 요청에 인증이 필요했지만 사용 가능한 토큰이 없습니다.
/// 인증 필요 요청에서 사용 가능한 토큰 미보유
case authenticationRequired
/// 요청에 인증이 필요했지만 인증 토큰 공급자가 설정되지 않았습니다.
/// 인증 필요 요청에서 `NXAuthTokenProvider` 미설정
case authProviderUnavailable
/// 전송 계층에서 `URLError`가 발생했습니다.
/// transport `URLError` 발생
case transport(URLError)
/// 요청이 시간 초과되었습니다.
/// 요청 타임아웃
case timeout
/// 요청이 취소되었습니다.
/// 요청 취소
case cancelled
/// 수신한 상태 코드에 대한 응답 유효성 검사가 실패했습니다.
/// 수신 상태 코드 응답 validation 실패
case invalidStatus(statusCode: Int, data: Data?)
/// 서버가 실패 상태 코드를 반환했고 사용자 정의 서버 오류로 디코딩되었습니다.
/// 실패 상태 코드 응답의 사용자 정의 서버 오류 decoding
case server(statusCode: Int, data: Data?, underlying: any Error)
/// 성공한 요청의 응답 디코딩이 실패했습니다.
/// 성공 요청 응답 decoding 실패
case decoding(any Error, data: Data?)
/// 분류되지 않은 오류가 발생했습니다.
/// 분류되지 않은 오류
case unknown(any Error)
}
2 changes: 1 addition & 1 deletion Sources/Core/NXHTTPMethod.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

/// Nexa 요청 빌더가 지원하는 HTTP 메서드입니다.
/// Nexa request builder 지원 HTTP method
public enum NXHTTPMethod: String, Sendable, Hashable {
case get = "GET"
case post = "POST"
Expand Down
72 changes: 36 additions & 36 deletions Sources/Core/NXLogging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

/// Nexa 로거가 내보내는 요청 라이프사이클 이벤트입니다.
/// Nexa logger가 내보내는 요청 lifecycle event
public enum NXLogEvent: Sendable {
case requestStart(NXRequestStartLog)
case requestEnd(NXRequestEndLog)
Expand All @@ -16,20 +16,20 @@ public enum NXLogEvent: Sendable {
case authRefresh(NXAuthRefreshLog)
}

/// 요청 시도 시작 시점에 출력되는 구조화된 페이로드입니다.
/// 요청 시도 시작 시점 구조화 payload
public struct NXRequestStartLog: Sendable {
/// 동일한 논리 요청의 모든 시도에서 공유되는 안정적 식별자입니다.
/// 동일한 논리 요청 시도 간 공유 안정적 식별자
public let requestIdentifier: UUID
/// 현재 시도 번호(`1`부터 시작)입니다.
/// 현재 시도 번호(`1`부터 시작)
public let attemptNumber: Int
/// 전송할 요청의 HTTP 메서드 문자열입니다.
/// 전송 HTTP 메서드 문자열
public let method: String
/// 완전히 해석된 요청 URL 문자열입니다.
/// 완전 해석된 요청 URL 문자열
public let url: String
/// 요청에 포함된 최종 헤더입니다.
/// 요청 최종 header
public let headers: [String: String]

/// 요청 시작 로그 페이로드를 생성합니다.
/// 요청 시작 log payload 생성
public init(
requestIdentifier: UUID,
attemptNumber: Int,
Expand All @@ -45,20 +45,20 @@ public struct NXRequestStartLog: Sendable {
}
}

/// 요청 시도가 성공적으로 끝났을 때 출력되는 구조화된 페이로드입니다.
/// 요청 성공 종료 시점 구조화 payload
public struct NXRequestEndLog: Sendable {
/// 동일한 논리 요청의 모든 시도에서 공유되는 안정적인 식별자입니다.
/// 동일한 논리 요청 시도 간 공유 안정적 식별자
public let requestIdentifier: UUID
/// 현재 시도 번호(`1`부터 시작)입니다.
/// 현재 시도 번호(`1`부터 시작)
public let attemptNumber: Int
/// 서버가 반환한 HTTP 상태 코드입니다.
/// 서버 반환 HTTP 상태 코드
public let statusCode: Int
/// 시도의 실제 경과 시간입니다.
/// 시도 실제 경과 시간
public let elapsedTime: TimeInterval
/// 응답 페이로드 크기(바이트)입니다.
/// 응답 payload 크기(byte)
public let payloadSize: Int

/// 요청 완료 로그 페이로드를 생성합니다.
/// 요청 완료 log payload 생성
public init(
requestIdentifier: UUID,
attemptNumber: Int,
Expand All @@ -74,18 +74,18 @@ public struct NXRequestEndLog: Sendable {
}
}

/// 요청 시도가 실패했을 때 출력되는 구조화된 페이로드입니다.
/// 요청 실패 시점 구조화 payload
public struct NXRequestFailureLog: Sendable {
/// 동일한 논리 요청의 모든 시도에서 공유되는 안정적인 식별자입니다.
/// 동일한 논리 요청 시도 간 공유 안정적 식별자
public let requestIdentifier: UUID
/// 현재 시도 번호(`1`부터 시작)입니다.
/// 현재 시도 번호(`1`부터 시작)
public let attemptNumber: Int
/// 시도의 실제 경과 시간입니다.
/// 시도 실제 경과 시간
public let elapsedTime: TimeInterval
/// 사람이 읽기 쉬운 실패 설명입니다.
/// 사람이 읽기 쉬운 실패 설명
public let errorDescription: String

/// 요청 실패 로그 페이로드를 생성합니다.
/// 요청 실패 log payload 생성
public init(
requestIdentifier: UUID,
attemptNumber: Int,
Expand All @@ -99,52 +99,52 @@ public struct NXRequestFailureLog: Sendable {
}
}

/// Nexa가 다음 재시도를 예약할 때 출력되는 구조화된 페이로드입니다.
/// Nexa 다음 retry 예약 시 출력 구조화 payload
public struct NXRetryLog: Sendable {
/// 동일한 논리 요청의 모든 시도에서 공유되는 안정적인 식별자입니다.
/// 동일한 논리 요청 시도 간 공유 안정적 식별자
public let requestIdentifier: UUID
/// 다음에 실행될 시도 번호입니다.
/// 다음 실행 시도 번호
public let nextAttemptNumber: Int
/// 다음 시도 시작 전 대기 시간입니다.
/// 다음 시도 시작 전 대기 시간
public let delay: TimeInterval

/// 재시도 로그 페이로드를 생성합니다.
/// retry log payload 생성
public init(requestIdentifier: UUID, nextAttemptNumber: Int, delay: TimeInterval) {
self.requestIdentifier = requestIdentifier
self.nextAttemptNumber = nextAttemptNumber
self.delay = delay
}
}

/// 인증 토큰 갱신 시도 종료 후 출력되는 구조화된 페이로드입니다.
/// 인증 토큰 갱신 시도 종료 후 출력 구조화 payload
public struct NXAuthRefreshLog: Sendable {
/// 갱신을 시작한 요청의 식별자입니다.
/// 갱신 시작 요청 식별자
public let requestIdentifier: UUID
/// 갱신 시도 성공 여부입니다.
/// 갱신 시도 성공 여부
public let succeeded: Bool

/// 인증 갱신 로그 페이로드를 생성합니다.
/// 인증 갱신 log payload 생성
public init(requestIdentifier: UUID, succeeded: Bool) {
self.requestIdentifier = requestIdentifier
self.succeeded = succeeded
}
}

/// Nexa의 구조화된 요청 라이프사이클 이벤트를 수신합니다.
/// Nexa의 구조화된 요청 lifecycle event 수신
///
/// ## 개요
///
/// 요청 라이프사이클 이벤트를 자체 로깅 또는 분석 파이프라인으로 전달하려면 `NXLogger`를 채택하세요.
/// 요청 lifecycle event의 자체 logging 또는 analytics pipeline 전달 대상 `NXLogger` 채택
public protocol NXLogger: Sendable {
/// Nexa가 발행한 로그 이벤트 한 건을 처리합니다.
/// Nexa 발행 log event 단건 처리
func log(_ event: NXLogEvent) async
}

/// 발생한 모든 이벤트를 무시하는 로거입니다.
/// 발생 event 전체 무시 logger
public struct NXNoopLogger: NXLogger {
/// 아무 작업도 수행하지 않는 로거를 생성합니다.
/// 무동작 logger 생성
public init() {}

/// 전달된 로그 이벤트를 무시합니다.
/// 전달 log event 무시
public func log(_ event: NXLogEvent) async {}
}
30 changes: 15 additions & 15 deletions Sources/Core/NXNetworkMetrics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@

import Foundation

/// 하나의 `URLSession` 작업에서 발생한 네트워크 활동의스냅샷입니다.
/// `URLSession` task 기반 네트워크 활동snapshot
///
/// `NXURLSessionTransport`는 이 값을 `NXNetworkMetricsObserver`에 전달하기 전에 생성합니다.
/// 사용자 정의 `NXHTTPTransport` 구현은 이 값을 생성하지 않습니다.
/// `NXURLSessionTransport`는 `NXNetworkMetricsObserver` 전달 전 snapshot 생성
/// 사용자 정의 `NXHTTPTransport` 구현은 snapshot 미생성
public struct NXNetworkMetrics: Sendable, Equatable {
/// URL 로딩 작업의 총 소요 시간입니다.
/// URL loading task 총 소요 시간
public let taskDuration: TimeInterval?
/// URL 로딩 작업이 따라간 리다이렉트 횟수입니다.
/// URL loading task redirect 횟수
public let redirectCount: Int
/// URL 로딩 작업에서 수집한 트랜잭션 개수입니다.
/// URL loading task 수집 transaction 개수
public let transactionCount: Int
/// `URLSession`이 보고한 순서를 보존한 트랜잭션 스냅샷입니다.
/// `URLSession` 보고 순서 보존 transaction snapshot
public let transactions: [NXNetworkTransactionMetrics]

/// 네트워크 메트릭 스냅샷을 생성합니다.
/// 네트워크 metrics snapshot 생성
public init(
taskDuration: TimeInterval?,
redirectCount: Int,
Expand All @@ -35,20 +35,20 @@ public struct NXNetworkMetrics: Sendable, Equatable {
}
}

/// 하나의 URL 로딩 트랜잭션에 대한 값 스냅샷입니다.
/// 단일 URL loading transaction 값 snapshot
public struct NXNetworkTransactionMetrics: Sendable, Equatable {
/// URLSession이 두 타임스탬프를 모두 보고한 경우의 DNS 조회 시간입니다.
/// `URLSession` 시작·종료 timestamp 제공 시 DNS 조회 시간
public let domainLookupDuration: TimeInterval?
/// URLSession이 두 타임스탬프를 모두 보고한 경우 연결 시작부터 종료까지의 시간입니다.
/// `URLSession` 시작·종료 timestamp 제공 시 연결 시작부터 종료까지의 시간
public let connectionDuration: TimeInterval?
/// URLSession이 두 타임스탬프를 모두 보고한 경우 TLS 협상 시간입니다.
/// `URLSession` 시작·종료 timestamp 제공 시 TLS 협상 시간
public let secureConnectionDuration: TimeInterval?
/// URLSession이 두 타임스탬프를 모두 보고한 경우 요청 시작부터 첫 바이트 응답 수신까지의 시간입니다.
/// `URLSession` 시작·종료 timestamp 제공 시 요청 시작부터 첫 응답 byte 수신까지의 시간
public let timeToFirstByte: TimeInterval?
/// URLSession이 기존 연결을 재사용했는지 여부입니다.
/// 기존 연결 재사용 여부
public let isConnectionReused: Bool

/// 트랜잭션 메트릭 스냅샷을 생성합니다.
/// transaction metrics snapshot 생성
public init(
domainLookupDuration: TimeInterval?,
connectionDuration: TimeInterval?,
Expand Down
6 changes: 3 additions & 3 deletions Sources/Core/NXNetworkMetricsObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
// Created by opfic on 8/23/26.
//

/// `NXURLSessionTransport`에서 수집한 메트릭 스냅샷을 수신합니다.
/// `NXURLSessionTransport` 수집 metrics snapshot 수신 대상
///
/// 메트릭 전달은 요청 완료와 로거 이벤트 순서와 독립적으로 수행됩니다.
/// 요청 완료 및 logger event 순서와 독립적 metrics 전달
public protocol NXNetworkMetricsObserver: Sendable {
/// 네트워크 메트릭 스냅샷을 한 건 기록합니다.
/// 네트워크 metrics snapshot 단건 기록
func record(_ metrics: NXNetworkMetrics) async
}
Loading