{"id":24806164,"url":"https://github.com/tdeleon/relax","last_synced_at":"2025-10-13T08:30:44.623Z","repository":{"id":40457845,"uuid":"263456544","full_name":"tdeleon/Relax","owner":"tdeleon","description":"Declaratively build and send client requests for REST APIs in Swift.","archived":false,"fork":false,"pushed_at":"2025-08-25T23:20:07.000Z","size":1412,"stargazers_count":18,"open_issues_count":11,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-09-28T17:46:34.832Z","etag":null,"topics":["combine","http","ios","linux","macos","networking","rest","rest-client","result-builder","swift","tvos","visionos","watchos","windows"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tdeleon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-05-12T21:30:23.000Z","updated_at":"2025-03-16T22:54:49.000Z","dependencies_parsed_at":"2025-08-08T01:21:43.920Z","dependency_job_id":null,"html_url":"https://github.com/tdeleon/Relax","commit_stats":{"total_commits":88,"total_committers":2,"mean_commits":44.0,"dds":0.05681818181818177,"last_synced_commit":"47b23ca34a1896f13b0e8d71df25e00bcef7cf8e"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/tdeleon/Relax","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdeleon%2FRelax","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdeleon%2FRelax/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdeleon%2FRelax/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdeleon%2FRelax/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tdeleon","download_url":"https://codeload.github.com/tdeleon/Relax/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdeleon%2FRelax/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279014326,"owners_count":26085492,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["combine","http","ios","linux","macos","networking","rest","rest-client","result-builder","swift","tvos","visionos","watchos","windows"],"created_at":"2025-01-30T08:19:24.030Z","updated_at":"2025-10-13T08:30:44.266Z","avatar_url":"https://github.com/tdeleon.png","language":"Swift","readme":"\n\u003ch1 style=\"text-align: center;\"\u003e\u003cimg src=\"https://user-images.githubusercontent.com/3507743/82412732-08c9c900-9a29-11ea-9eb4-0f7caea45e6e.png\" height=\"60\" style=\"vertical-align: middle; padding-right: 20px\"\u003eRelax\u003c/h1\u003e\n\n---\n\n[![License](https://img.shields.io/github/license/tdeleon/Relax)](https://github.com/tdeleon/Relax/blob/master/LICENSE)\n[![Swift](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Ftdeleon%2FRelax%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/tdeleon/Relax)\n[![SwiftPM](https://img.shields.io/badge/SwiftPM-compatible-brightgreen)](https://swift.org/package-manager/)\n[![Platforms](https://img.shields.io/badge/Platforms-macOS%20%7C%20iOS%20%7C%20watchOS%20%7C%20tvOS%20%7C%20Linux%20%7C%20Windows-blue)](https://www.swift.org/platform-support/)\n[![Test](https://github.com/tdeleon/Relax/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/tdeleon/Relax/actions/workflows/test.yml?query=branch%3Amain++)\n\n*Declaratively build and send client requests for REST APIs in Swift.*\n\n## Overview\n\nRelax provides a way to declaratively define and organize client HTTP requests for REST APIs. The framework is\nlightweight built on protocols, easily allowing you to structure your requests for even the most complex REST APIs.\n\n### Full Reference Documentation\n\nhttps://swiftpackageindex.com/tdeleon/relax/documentation\n\n### Features\n\n- **Lightweight:** built on protocols, works directly on URLSession for low overhead\n- **Declarative syntax:** using [result builders](https://docs.swift.org/swift-book/LanguageGuide/AdvancedOperators.html#ID630),\nallows for quickly and easily organizing requests to match any structure of REST API.\n- **Modern:** Supports [Swift concurrency](https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html)\n(`async`/`await`) and [Combine](https://developer.apple.com/documentation/combine) (on Apple platforms).\n\n### Supported Platforms\n\nAvailable for all Swift (5.7+) platforms, including:\n\n| Platform | Minimum Version |\n|----------|-----------------|\n| macOS    | 12.0            |\n| iOS      | 14.0            |\n| watchOS  | 7.0             |\n| tvOS     | 14.0            |\n| Linux    | Swift 5.7*      |\n| Windows  | Swift 5.7*      |\n\n*Works on any version where Swift 5.7 is supported.\n\n### Getting Started\n\nRelax supports the [Swift Package Manager](https://www.swift.org/package-manager/). To integrate in your project-\n\n#### Using a Package Manifest File\n\n1. Add the following to the **package** dependencies in the *Package.swift* manifest file:\n\n    ```swift\n    dependencies: [\n        .package(url: \"https://github.com/tdeleon/Relax.git\", from: \"2.0.0\")\n    ]\n    ```\n\n2. Add *Relax* to the **target** dependencies:\n\n    ```swift\n    targets: [\n        .target(\n            name: \"YourProject\",\n            dependencies: [\"Relax\"])\n    ]\n    ```\n\n#### Using an Xcode Project\n\n1. In your project, choose **File \u003e Add Package Dependencies...**\n\n2. Select the desired criteria, and click **Add Package**\n\n3. In the Package Product selection dialog, select **your target** in the *Add to Target* column for the *Package Product*\n**Relax**. Leave **URLMock** set to **None**, unless you have a test target.\n\n4. Click on **Add Package**\n\n\u003eTip: `URLMock` is an additional framework provided to aid in testing by mocking responses to requests, and should be\nadded to your test targets only. For more information, see [Testing](#testing) below.\n\n#### Import the framework\n\nIn files where you will be using Relax, import the framework:\n\n```swift\nimport Relax\n```\n\n### Make Requests\n\nYou can make very simple requests:\n```swift\ndo {\n    let request = Request(.get, url: URL(string: \"https://example.com/users\")!)\n    try await request.send()\n} catch {\n    print(error)\n}\n```\nOr, more complex requests with multiple properties:\n```swift\nlet request = Request(.post, url: URL(string: \"https://example.com/users\")!) {\n    Body {\n        // Send an Encodable user object as JSON in the request body\n        User(name: \"firstname\")\n    }\n    Headers {\n        Header.authorization(.basic, value: \"secret-123\")\n        Header.contentType(.applicationJSON)\n    }\n}\n```\n\nSee [Defining Requests](https://swiftpackageindex.com/tdeleon/relax/documentation/relax/definingrequests) for more\ndetails.\n\n### Define a Complex API Structure\n\nYou can organize groups of requests into structures of ``Service``s and ``Endpoint``s, inheriting a common base URL and\nproperties:\n\n```swift\nenum UserService: Service {\n    static let baseURL = URL(string: \"https://example.com/\")!\n    // Define shared properties for any request/endpoint children\n    static var sharedProperties: Request.Properties {\n        Headers {\n            Header.authorization(.basic, value: \"secretpassword\")\n        }\n    }\n\n    // define a /users endpoint\n    enum Users: Endpoint {\n        // /users appended to base URL: https://example.com/users\n        static let path = \"users\"\n        // connect Users to UserService\n        typealias Parent = UserService\n\n        // GET request\n        static var getAll = Request(.get, parent: UserService.self)\n    }\n}\n\n// make a get request to https://example.com/users\nlet users = try await UserService.Users.getAll.send()\n```\n\nSee [Defining an API Structure](https://swiftpackageindex.com/tdeleon/relax/documentation/relax/definingapistructure) for\nmore details.\n\n## Testing\n\n[URLMock](https://swiftpackageindex.com/tdeleon/relax/documentation/urlmock) is a framework for mocking responses to\n`URLSession` requests, and is included in the Relax package as a second library target. \n\nThis allows you to test all ``Request``s by using a `URLSession` that returns mock content only, never making a real\nrequest over the network. Convenience methods are provided for common responses such as HTTP status codes, JSON, and\nerrors.\n\nTo use, simply add `URLMock` as a dependency in your `Package.swift` file or in Xcode to your test target(s):\n\n```swift\n.testTarget(\n    name: \"MyAppTests\",\n    dependencies: [\"Relax\", \"URLMock\"]),\n```\n\n\u003eNote: The `URLMock` framework is intended for testing use only. It is highly encouraged to include it as a\ndependency in your test targets only.\n\nNext, in your tests, include the `URLMock` framework along with `Relax` and the target being tested:\n\n```swift\nimport XCTest\nimport Relax\nimport URLMock\n@testable import MyApp\n```\nFinally, create a `URLSession` providing a mocked response, and use it with a ``Request``:\n\n```swift\n// Create a session which returns a URLError\nlet session = URLMock.session(.mock(.notConnectedToInternet))\n// Make a request using the modified session. An error should be thrown\ndo {\n    try await MyAPIService.Endpoint.get.send(session: session)\n    XCTAssertFail(\"Should have failed\")\n} catch {\n    // Validate error is handled correctly\n}\n```\n\nFor further examples, see the [full documentation](https://swiftpackageindex.com/tdeleon/relax/documentation/urlmock).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftdeleon%2Frelax","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftdeleon%2Frelax","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftdeleon%2Frelax/lists"}