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/Package.swift b/Package.swift
index 6fa8241..c0b5a29 100644
--- a/Package.swift
+++ b/Package.swift
@@ -15,7 +15,8 @@ let package = Package(
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
- name: "SwiftDevRant"),
+ name: "SwiftDevRant"
+ ),
.testTarget(
name: "SwiftDevRantTests",
dependencies: ["SwiftDevRant"]
diff --git a/Sources/SwiftDevRant/DevRantBackend.swift b/Sources/SwiftDevRant/DevRantBackend.swift
new file mode 100644
index 0000000..14bda95
--- /dev/null
+++ b/Sources/SwiftDevRant/DevRantBackend.swift
@@ -0,0 +1,3 @@
+struct DevRantBackend: Backend {
+ let baseURL = "https://devrant.com/api/"
+}
diff --git a/Sources/SwiftDevRant/Request/Backend.swift b/Sources/SwiftDevRant/Request/Backend.swift
new file mode 100644
index 0000000..a823620
--- /dev/null
+++ b/Sources/SwiftDevRant/Request/Backend.swift
@@ -0,0 +1,3 @@
+public protocol Backend {
+ var baseURL: String { get }
+}
diff --git a/Sources/SwiftDevRant/Request/Request.swift b/Sources/SwiftDevRant/Request/Request.swift
new file mode 100644
index 0000000..ab7faf4
--- /dev/null
+++ b/Sources/SwiftDevRant/Request/Request.swift
@@ -0,0 +1,64 @@
+import Foundation
+
+public struct Request {
+ public enum Error: Swift.Error, CustomStringConvertible {
+ case notHttpResponse
+ case notFound
+ case apiError(_ error: ApiError)
+ case generalError
+
+ public var description: String {
+ switch self {
+ case .notHttpResponse: "response is not HTTP"
+ case .notFound: "Not found"
+ case .apiError(error: let error): "\(error)"
+ case .generalError: "General error"
+ }
+ }
+ }
+
+ struct EmptyError: Decodable {
+
+ }
+
+ public enum Method: String {
+ case get = "GET"
+ case post = "POST"
+ case put = "PUT"
+ case delete = "DELETE"
+ case patch = "PATCH"
+ }
+
+ public struct Config {
+ let method: Method
+ let backend: Backend
+ let path: String
+ var urlParameters: [String: String] = [:]
+ var headers: [String: String] = [:]
+ }
+
+ var session = URLSession(configuration: .ephemeral)
+
+ func makeURLRequest(config: Config, body: Data?) -> URLRequest {
+ let urlQuery = urlEncodedQueryString(from: config.urlParameters)
+ guard let url = URL(string: config.backend.baseURL + config.path + urlQuery) else {
+ fatalError("Couldn't create a URL")
+ }
+ var urlRequest = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData)
+ urlRequest.httpMethod = config.method.rawValue
+ urlRequest.httpBody = body
+ config.headers.forEach {
+ urlRequest.setValue($0.value, forHTTPHeaderField: $0.key)
+ }
+ return urlRequest
+ }
+
+ func urlEncodedQueryString(from query: [String: String]) -> String {
+ guard !query.isEmpty else { return "" }
+ var components = URLComponents()
+ components.queryItems = query.map { URLQueryItem(name: $0.key, value: $0.value) }
+ let absoluteString = components.url?.absoluteString ?? ""
+ let plusCorrection = absoluteString.replacingOccurrences(of: "+", with: "%2b")
+ return plusCorrection
+ }
+}