EagleNet

2.1.1

Simple lightweight networking layer written on top of URLSession. This will provide a clean, separate layer for networking.
AnbalaganD/EagleNet

What's New

2.1.1

2026-03-25T16:34:40Z
  • Fix minor issue

Full Changelog: 2.1.0...2.1.1

This library aims to provide a simple and elegant approach to writing network requests. It's designed to be lightweight, adding a thin layer on top of URLSession without excessive engineering overhead.

Our primary objectives are:

  • Lightweight networking library: Keep the library small and efficient.
  • Easy to maintain: Prioritize clear code and modular design for maintainability.
  • Beginner friendly: Make the library accessible to developers of all levels.
  • Well documented: Provide comprehensive documentation to guide usage.
  • Customizable and testable: Allow for flexibility and ensure code quality through testing.

Currently, this library supports basic HTTP data requests (GET, POST, PUT, DELETE), custom HTTP methods, file uploading using multipart/form-data, and direct-to-disk file downloading. These capabilities address the majority of network communication needs in most applications.

For detailed information on feature status, please refer to the Roadmap file.

See the complete documentation here: Documentation

Swift Package Manager (SPM)

EagleNet is available through SPM. Use the URL below to add it as a dependency.

dependencies: [
    .package(url: "https://github.com/AnbalaganD/EagleNet", .upToNextMajor(from: "2.1.1"))
]

Making a GET Request

import EagleNet

struct User: Decodable {
    let id: Int
    let name: String
    let email: String
}

// Basic GET request
let user: User = try await EagleNet.get(
    url: "https://api.example.com/users/1"
)

// Get raw response data
let (data, response) = try await EagleNet.get(
    url: "https://api.example.com/users/1"
)

Making a POST Request

struct CreateUser: Encodable {
    let name: String
    let email: String
}

struct UserResponse: Decodable {
    let id: Int
    let name: String
}

let newUser = CreateUser(name: "Anbalagan D", email: "anbu94p@gmail.com")
let response: UserResponse = try await EagleNet.post(
    url: "https://api.example.com/users",
    body: newUser
)

// Get raw response data
let (data, urlResponse) = try await EagleNet.post(
    url: "https://api.example.com/users",
    body: newUser
)

File Upload

let imageData = // ... your image data ...
let response: UploadResponse = try await EagleNet.upload(
    url: "https://api.example.com/upload",
    parameters: [
        .file(
            key: "avatar",
            fileName: "profile.jpg",
            data: imageData,
            mimeType: .jpegImage
        ),
        .text(key: "username", value: "Anbu")
    ],
    progress: { bytesTransferred, totalBytes in
        let progress = Float(bytesTransferred) / Float(totalBytes)
        print("Upload progress: \(Int(progress * 100))%")
    }
)

// Get raw response data
let (data, urlResponse) = try await EagleNet.upload(
    url: "https://api.example.com/upload",
    parameters: [
        .file(key: "avatar", fileName: "profile.jpg", data: imageData, mimeType: .jpegImage)
    ]
)

File Download

let destinationDirectory = URL(fileURLWithPath: "/path/to/downloads")

let (localURL, response) = try await EagleNet.download(
    url: "https://example.com/large-video.mp4",
    destinationDirectory: destinationDirectory,
    progress: { bytesDownloaded, totalBytes in
        let progress = Float(bytesDownloaded) / Float(totalBytes)
        print("Download progress: \(Int(progress * 100))%")
    }
)

destinationDirectory must resolve to a local file:// URL and point to a directory.

  • NetworkError.invalidFileURL is thrown when the value is not a local file URL.
  • NetworkError.invalidDirectoryPath is thrown when the value points to a file instead of a directory.

Note: Background downloads and pause/resume tracking are currently not supported. Downloads will be cancelled if the application goes into the background or is terminated.

Request Interceptors

struct AuthInterceptor: RequestInterceptor {
    let token: String
    
    func modify(request: consuming URLRequest) async throws -> URLRequest {
        request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
        return request
    }
}

// Add interceptor to network service
EagleNet.addRequestInterceptor(
    AuthInterceptor(token: "your-auth-token")
)

Response Interceptors

struct LoggingInterceptor: ResponseInterceptor {
    func modify(data: consuming Data, urlResponse: consuming URLResponse) async throws -> (Data, URLResponse) {
        if let httpResponse = urlResponse as? HTTPURLResponse {
            print("Response Status Code: \(httpResponse.statusCode)")
            print("Response Headers: \(httpResponse.allHeaderFields)")
            
            if let responseString = String(data: data, encoding: .utf8) {
                print("Response Body: \(responseString)")
            }
        }
        return (data, urlResponse)
    }
}

// Add response interceptor to network service
EagleNet.addResponseInterceptor(LoggingInterceptor())

Custom HTTP Methods

// Using custom HTTP methods like PATCH
struct UpdateStatus: Encodable {
    let status: String
}

let patchRequest = DataRequest(
    url: "https://api.example.com/users/1",
    httpMethod: .custom("PATCH"),
    body: UpdateStatus(status: "active")
)

let response: User = try await EagleNet.execute(patchRequest)

Configuration

// Custom URLSession configuration
let customService = EagleNet.defaultService(
    urlSession: URLSession(configuration: .ephemeral),
    jsonEncoder: JSONEncoder(),
    jsonDecoder: JSONDecoder(),
    fileManager: .default
)

EagleNet.configure(networkService: customService)

Author

Anbalagan D

License

EagleNet is available under the MIT license. See the LICENSE file for more info.

Description

  • Swift Tools 5.9.0
View More Packages from this Author

Dependencies

  • None
Last updated: Sun Mar 29 2026 19:21:58 GMT-0900 (Hawaii-Aleutian Daylight Time)