PascalCase decoding strategy

This commit is contained in:
2026-10-19 13:54:34 -07:00
parent 8b6d4fe751
commit 0b2598f666
3 changed files with 45 additions and 9 deletions
+6 -1
View File
@@ -7,6 +7,9 @@
import Foundation import Foundation
/// Every `Request` must pass through this `Client`.
/// Manages merging `Request` and default headers as well as creating the `URLRequest`.
/// Provides its own `JSONDecoder` and `JSONEncoder` with a PascalCase `CodingKey` strategy.
public struct Client { public struct Client {
// MARK: - Properties // MARK: - Properties
private let server: String private let server: String
@@ -20,6 +23,8 @@ public struct Client {
self.server = server self.server = server
self.session = session self.session = session
self.defaultHeaders = headers self.defaultHeaders = headers
decoder.keyDecodingStrategy = .convertFromPascalCase
} }
/// When all a client needs is the HTTP status code of an endpoint, this function should be used. /// When all a client needs is the HTTP status code of an endpoint, this function should be used.
@@ -43,7 +48,7 @@ public struct Client {
func dataRequest<T>(_ request: any Request) async throws -> T? where T: Codable { func dataRequest<T>(_ request: any Request) async throws -> T? where T: Codable {
let urlRequest = try createRequestObject(for: request) let urlRequest = try createRequestObject(for: request)
let (data, response) = try await session.data(for: urlRequest) let (data, response) = try await session.data(for: urlRequest)
guard let response = response as? HTTPURLResponse else { guard response is HTTPURLResponse else {
throw RequestError.invalidResponse throw RequestError.invalidResponse
} }
@@ -0,0 +1,39 @@
//
// PascalCaseKey+KeyDecodingStrategy.swift
// JellyKit
//
// Created by Alex Loren on 10/19/26.
//
import Foundation
extension JSONDecoder.KeyDecodingStrategy {
// MARK: - Computed Properties
/// A key decoding strategy that converts pascal-case keys to camel-case keys.
static var convertFromPascalCase: Self {
.custom { codingPath in
let key = codingPath.last!.stringValue
let converted = key.prefix(1).lowercased() + key.dropFirst()
return PascalCaseKey(stringValue: converted)
}
}
}
/// Simply a reusable `CodingKey` for converting PascalCase to camelCase.
private struct PascalCaseKey: CodingKey {
// MARK: - Properties
let stringValue: String
let intValue: Int?
// MARK: - Functions
init(stringValue: String) {
self.stringValue = stringValue
intValue = nil
}
init?(intValue: Int) {
stringValue = String(intValue)
self.intValue = intValue
}
}
-8
View File
@@ -25,12 +25,4 @@ struct User: Codable {
/// If not `nil` a request can be made to retreive the profile image for the `User`. /// If not `nil` a request can be made to retreive the profile image for the `User`.
var primaryImageTag: String? var primaryImageTag: String?
enum CodingKeys: String, CodingKey {
case id = "Id"
case serverId = "ServerId"
case name = "Name"
case hasPassword = "HasPassword"
case primaryImageTag = "PrimaryImageTag"
}
} }