Skip to content

Commit

Permalink
Add Networking to Later
Browse files Browse the repository at this point in the history
  • Loading branch information
0xLeif committed Nov 16, 2024
1 parent 04ae281 commit d8e4505
Show file tree
Hide file tree
Showing 12 changed files with 763 additions and 5 deletions.
10 changes: 5 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import PackageDescription
let package = Package(
name: "Later",
platforms: [
.macOS(.v10_15),
.iOS(.v13),
.tvOS(.v13),
.watchOS(.v6),
.macCatalyst(.v13),
.macOS(.v13),
.iOS(.v16),
.tvOS(.v16),
.watchOS(.v9),
.macCatalyst(.v16),
.visionOS(.v1)
],
products: [
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
- **Stream**: Represents an asynchronous sequence of values emitted over time, perfect for handling data that updates periodically.
- **Publisher**: Allows objects to subscribe to changes in state or data, notifying subscribers when updates occur, ensuring your application responds dynamically to changes.
- **Subscribing**: A protocol for objects that want to observe changes in state or data, making it easy to react to updates.
- **Simple and Intuitive API**: Make various HTTP requests (GET, POST, PUT, DELETE, etc.) with ease.
- **Flexible Request Handling**: Comprehensive support for request headers, URL encoding, and request bodies.
- **Asynchronous Requests**: Utilize Swift's `async/await` syntax for asynchronous network requests.
- **Customizable URLSession**: Customize and configure URLSession with default or custom configurations.
- **Mocking Support**: Easily mock network requests for simplified testing and development.

## Getting Started

Expand All @@ -32,6 +37,7 @@ Here’s a breakdown of the **Later** documentation:
- [Stream Usage](documentation/usage-stream.md)
- [Publisher and Subscribing Usage](documentation/usage-publisher.md)
- [Schedule Task Usage](documentation/usage-schedule-task.md)
- [Networking](documentation/networking.md)
- [Contributing](documentation/contributing.md): Information on how to contribute to the **Later** project.

## Next Steps
Expand Down
26 changes: 26 additions & 0 deletions Sources/Later/Network/API.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Foundation

/// An open class that defines the base API. It will request data from a network pointing to a specific API endpoint.
open class API<APIEndpoint: Endpoint> {
private let network: Networking

/// Initializes a new instance of the API class.
public init() {
network = Network()
}

/**
Sends an asynchronous network request to a specific API endpoint.
- Parameter endpoint: The API endpoint to which the request will be sent.
- Throws: If there is an error during the network request.
- Returns: The data response from the network request.
*/
open func request(_ endpoint: APIEndpoint) async throws -> DataResponse {
try await network.request(
for: APIEndpoint.url.appending(path: endpoint.path),
method: endpoint.method,
headerFields: endpoint.headers,
body: endpoint.body
)
}
}
26 changes: 26 additions & 0 deletions Sources/Later/Network/DataResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Foundation

/// Represents a response containing data and a URL response.
public struct DataResponse {
/// The data received in the response.
public let data: Data?

/// The URL response received from the server.
public let response: URLResponse?

/// Initializes a `DataResponse` with the given data and URL response.
/// - Parameters:
/// - data: The data received in the response.
/// - response: The URL response received from the server.
public init(data: Data?, response: URLResponse?) {
self.data = data
self.response = response
}

/// Initializes a `DataResponse` with a tuple containing data and URL response.
/// - Parameters:
/// - tuple: A tuple containing data as the first element and URL response as the second element.
public init(_ tuple: (Data?, URLResponse?)) {
self.init(data: tuple.0, response: tuple.1)
}
}
31 changes: 31 additions & 0 deletions Sources/Later/Network/Endpoint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Foundation

/**
This protocol defines the basic structure of an endpoint in a HTTP network request.
- Note:
This protocol requires any conforming type to provide the necessary properties for constructing a HTTP request.
- Properties:
- `url`: The base URL for the endpoint.
- `method`: The HTTP request method (GET, POST, etc.)
- `path`: The path component of the URL.
- `headers`: The HTTP headers to include in the request.
- `body`: The body of the HTTP request, if any.
*/
public protocol Endpoint: Hashable {
/// The base URL for the endpoint.
static var url: URL { get }

/// The HTTP request method (GET, POST, etc.)
var method: HTTPRequestMethod { get }

/// The path component of the URL.
var path: String { get }

/// The HTTP headers to include in the request.
var headers: [String: String] { get }

/// The body of the HTTP request, if any.
var body: Data? { get }
}
29 changes: 29 additions & 0 deletions Sources/Later/Network/HTTPRequestMethod.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/// Represents HTTP request methods.
public enum HTTPRequestMethod: String {
/// The HTTP GET method.
case GET

/// The HTTP HEAD method.
case HEAD

/// The HTTP POST method.
case POST

/// The HTTP PUT method.
case PUT

/// The HTTP DELETE method.
case DELETE

/// The HTTP CONNECT method.
case CONNECT

/// The HTTP OPTIONS method.
case OPTIONS

/// The HTTP TRACE method.
case TRACE

/// The HTTP PATCH method.
case PATCH
}
42 changes: 42 additions & 0 deletions Sources/Later/Network/MockAPI.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
An open class that inherits from the base API class. It overrides the request method
to use a mock network for testing purposes.
- Parameter APIEndpoint: The endpoint where the API will point.
- Returns: A mocked data response for testing.
Usage:
```swift
let mockAPI = MockAPI<MyEndpoint>()
let response = try await mockAPI.request(.someEndpoint)
```
This will return a mock response using the data provided in the mockEndpoint body.
*/
open class MockAPI<APIEndpoint: Endpoint>: API<APIEndpoint> {
/**
Sends an asynchronous network request to a specific API endpoint using a mock network.
- Parameter endpoint: The API endpoint to which the request will be sent.
- Throws: If there is an error during the network request.
- Returns: A mocked data response for testing. The data will just be the body of the request and there will be no response.
*/
open override func request(_ endpoint: APIEndpoint) async throws -> DataResponse {
try await MockNetwork(
responseData: endpoint.body,
response: nil
)
.request(
for: APIEndpoint.url.appending(path: endpoint.path),
method: endpoint.method,
headerFields: endpoint.headers,
body: endpoint.body
)
}
}
34 changes: 34 additions & 0 deletions Sources/Later/Network/MockNetwork.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Foundation

/// A class that implements the `Networking` protocol to provide mock network responses.
open class MockNetwork: Network {
private let responseData: Data?
private let response: URLResponse?

public init(
responseData: Data?,
response: URLResponse?
) {
self.responseData = responseData
self.response = response
}

/// Sends an Mock HTTP request.
/// - Parameters:
/// - url: The URL to which the request will be sent.
/// - method: The HTTP method to be used.
/// - headerFields: Header fields to include in the request.
/// - body: Optional body to be including with the request.
/// - Returns: A `DataResponse` object containing the response data and URL response.
public override func request(
for url: URL,
method: HTTPRequestMethod,
headerFields: [String: String],
body: Data?
) async throws -> DataResponse {
DataResponse(
data: responseData,
response: response
)
}
}
Loading

0 comments on commit d8e4505

Please sign in to comment.