diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Sources/JellyKit/Client.swift b/Sources/JellyKit/Client.swift new file mode 100644 index 0000000..ebc5bf1 --- /dev/null +++ b/Sources/JellyKit/Client.swift @@ -0,0 +1,67 @@ +// +// Client.swift +// JellyKit +// +// Created by Alex Loren on 10/10/26. +// + +import Foundation + +struct Client { + // MARK: - Properties + private let session: URLSession + private let defaultHeaders: [String:String] + private let server: String + private let decoder: JSONDecoder = .init() + private let encoder: JSONEncoder = .init() + + // MARK: - Functions + init(server: String, session: URLSession = .shared, headers: [String:String] = [:]) { + self.server = server + self.session = session + self.defaultHeaders = headers + } + + func statusRequest(_ request: any Request) async throws -> Int { + do { + let urlRequest = try createRequestObject(for: request) + let (_, response) = try await session.data(for: urlRequest) + guard let response = response as? HTTPURLResponse else { + throw RequestError.invalidResponse + } + + return response.statusCode + } catch { + throw RequestError.unknown(message: error.localizedDescription) + } + } + + func dataRequest(_ request: any Request) async throws -> T? where T: Codable { + do { + let urlRequest = try createRequestObject(for: request) + let (data, response) = try await session.data(for: urlRequest) + guard let response = response as? HTTPURLResponse else { + throw RequestError.invalidResponse + } + + return try decoder.decode(T.self, from: data) + } catch { + throw RequestError.unknown(message: error.localizedDescription) + } + } + + private func createRequestObject(for request: Request) throws -> URLRequest { + guard let url = URL(string: "\(server)\(request.endpoint)") else { + throw RequestError.badURL + } + + let headers = defaultHeaders.merging(request.headers ?? [:]) { (current, new) in + return new + } + + var urlRequest = URLRequest(url: url) + urlRequest.httpMethod = request.method + urlRequest.allHTTPHeaderFields = headers + return urlRequest + } +} diff --git a/Sources/JellyKit/Enums/RequestError.swift b/Sources/JellyKit/Enums/RequestError.swift new file mode 100644 index 0000000..0ddff1f --- /dev/null +++ b/Sources/JellyKit/Enums/RequestError.swift @@ -0,0 +1,14 @@ +// +// RequestError.swift +// JellyKit +// +// Created by Alex Loren on 10/13/26. +// + +import Foundation + +enum RequestError: Error { + case badURL + case invalidResponse + case unknown(message: String?) +} diff --git a/Sources/JellyKit/JellyKit.swift b/Sources/JellyKit/JellyKit.swift deleted file mode 100644 index 8d0c09a..0000000 --- a/Sources/JellyKit/JellyKit.swift +++ /dev/null @@ -1,5 +0,0 @@ -// The Swift Programming Language -// https://docs.swift.org/swift-book -public func hello() { - print("Hello, world!") -} \ No newline at end of file diff --git a/Sources/JellyKit/Models/User.swift b/Sources/JellyKit/Models/User.swift new file mode 100644 index 0000000..e4520e7 --- /dev/null +++ b/Sources/JellyKit/Models/User.swift @@ -0,0 +1,22 @@ +// +// User.swift +// JellyKit +// +// Created by Alex Loren on 10/13/26. +// + +struct User: Codable { + var id: String + var serverId: String + var name: String + var hasPassword: Bool + var primaryImageTag: String + + enum CodingKeys: String, CodingKey { + case id = "Id" + case serverId = "ServerId" + case name = "Name" + case hasPassword = "HasPassword" + case primaryImageTag = "PrimaryImageTag" + } +} diff --git a/Sources/JellyKit/Protocols/Request.swift b/Sources/JellyKit/Protocols/Request.swift new file mode 100644 index 0000000..3549b36 --- /dev/null +++ b/Sources/JellyKit/Protocols/Request.swift @@ -0,0 +1,15 @@ +// +// Request.swift +// JellyKit +// +// Created by Alex Loren on 10/13/26. +// + +import Foundation + +protocol Request { + // MARK: - Properties + var endpoint: String { get set } + var method: String { get set } + var headers: [String:String]? { get set } +}