{"id":20534009,"url":"https://github.com/nzrsky/codablerequest","last_synced_at":"2026-02-08T19:01:45.500Z","repository":{"id":199050660,"uuid":"702040423","full_name":"nzrsky/CodableRequest","owner":"nzrsky","description":"Structured HTTP URLRequest and API client for Swift","archived":false,"fork":false,"pushed_at":"2024-10-28T18:27:56.000Z","size":569,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-16T00:26:21.896Z","etag":null,"topics":["api","ios","json","macos","rest","swift","urlrequest"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nzrsky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"nzrsky"}},"created_at":"2023-10-08T10:24:50.000Z","updated_at":"2024-06-05T13:08:46.000Z","dependencies_parsed_at":"2024-11-16T00:34:59.932Z","dependency_job_id":null,"html_url":"https://github.com/nzrsky/CodableRequest","commit_stats":{"total_commits":113,"total_committers":9,"mean_commits":"12.555555555555555","dds":0.663716814159292,"last_synced_commit":"9c4b01be168b3e622b74be03344e92c81802de94"},"previous_names":["nzrsky/codablerequest"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nzrsky%2FCodableRequest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nzrsky%2FCodableRequest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nzrsky%2FCodableRequest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nzrsky%2FCodableRequest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nzrsky","download_url":"https://codeload.github.com/nzrsky/CodableRequest/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234206206,"owners_count":18796273,"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","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":["api","ios","json","macos","rest","swift","urlrequest"],"created_at":"2024-11-16T00:24:49.472Z","updated_at":"2026-02-08T19:01:40.462Z","avatar_url":"https://github.com/nzrsky.png","language":"Swift","funding_links":["https://github.com/sponsors/nzrsky"],"categories":[],"sub_categories":[],"readme":"![CodableRequest](https://raw.githubusercontent.com/nzrsky/CodableRequest/main/Resources/header.png)\n\n# Structured HTTP URLRequest and API client for Swift\n\n[![Danger Swift](https://github.com/nzrsky/CodableRequest/actions/workflows/danger.yml/badge.svg)](https://github.com/nzrsky/CodableRequest/actions/workflows/danger.yml)\n[![Codecov](https://codecov.io/gh/nzrsky/CodableRequest/branch/main/graph/badge.svg)](https://codecov.io/gh/nzrsky/CodableRequest)\n\n\u003cdiv align=\"center\"\u003e\n\u003c!-- \t\u003ca href=\"https://github.com/nzrsky/CodableRequest/actions\"\u003e\n\t\t\u003cimg src=\"https://github.com/nzrsky/CodableRequest/workflows/Build,%20Lint%20\u0026%20Test/badge.svg\" alt=\"GitHub Actions\"\u003e\n\t\u003c/a\u003e\n\t\u003ca href=\"https://nzrsky.github.io/CodableRequest/\"\u003e\n\t\t\u003cimg src=\"https://raw.githubusercontent.com/nzrsky/CodableRequest/gh-pages/badge.svg\"/\u003e\n\t\u003c/a\u003e --\u003e\n\u003c/div\u003e\n\nCodableRequest is a pure Swift framework for building URLRequests using property wrappers. It's a fork of __Postie__ library\n\n \n## Example\n\nCheckout this full example starting at defining the request and the expected response, up to creating a client and sending it to the remote endpoint.\n\n```swift\nimport Foundation\nimport CodableRequest\n\n// Request contains body data encoded as a JSON\nstruct MyRequest: JSONRequest {\n\n    // The request body is strongly typed defined\n    struct RequestBody: Encodable {\n        var someNumberValue: Int\n    }\n\n    // Define the response directly inside the request, so every\n    // Request-Response are isolated.\n    // Also directly define, that the response body shall be decoded\n    // from JSON\n    struct Response: JSONDecodable {\n\n        // The expected response body structure\n        struct Body: Decodable {\n            var someNumberValue: Int\n        }\n\n        // The expected response body structure, in case we did something wrong\n        struct ErrorBody: Decodable {\n            var message: String\n        }\n\n        // Property wrappers define the purpose\n        @ResponseBody\u003cBody\u003e var body\n        @ErrorBody\u003cErrorBody\u003e var errorBody\n\n        // Access specific response headers\n        @ResponseHeader\u003cDefaultStrategy\u003e var contentType: String\n\n        // Status codes also have convenience utilities\n        @ResponseStatusCode var statusCode\n\n        // Cookies send by the remote\n        @Cookies var cookies\n    }\n\n    // The `keyEncodingStrategy` determines how to encode a type’s coding keys as JSON keys.\n    // The default value return `.convertToSnakeCase` but you can optionally choose to return `.useDefaultKeys` by implementing JSONRequest's protocol requirement as follow:\n    // static var keyEncodingStrategy: JSONEncoder.KeyEncodingStrategy {\n    //     .useDefaultKeys\n    // }\n    \n    // static var dateEncodingStrategy: JSONEncoder.DateEncodingStrategy {\n    //     .iso8601\n    // }\n\n\n    // This property holds the data which will be encoded\n    var body: RequestBody\n\n    // Location of our resource with template string\n    Path var path = \"/profile/{user_id}\"\n\n    // Parameter to replace in the template string\n    PathParameter(name: \"userId\") var userId: String\n\n    // HTTP method that shall be used\n    @HTTPMethod var method = .post\n\n    // Set request headers using the property naming\n    @Header var authorization: String?\n    \n    // Set multiple instances of HTTPCookie\n    @Cookies var cookies\n}\n\n// Create a request\nvar request = MyRequest(body: MyRequest.RequestBody(someNumberValue: 42),\n                        userId: \"my-user-id\")\nrequest.authorization = \"Bearer my-oauth-token\"\n\n// Create a client\nlet client = CodableURLSession(\n    url: URL(string: \"https://example.org\")!, \n    retryStrategy: .default\n)\n\n// Send the request with Combine\nclient.sendPublisher(request)\n    .sink { result in\n        switch result {\n        case .failure(let error):\n            print(\"Oh no something went wrong :(\")\n            print(error)\n        case .finished:\n            print(\"Everything worked fine :)\")\n        }\n    } receiveValue: { response in\n        // The single response object contains all the interesting data\n        print(response.statusCode)\n        print(response.body)\n        print(response.errorBody)\n        print(response.contentType)\n    }\n```\n\n## Core Concept\n\nThe networking layer of `Foundation` (and with `Combine`) is already quite advanced.\nUsing `URLRequest` you can set many different configuration values, e.g. the HTTP Method or Headers.\n\nUnfortunately you still need to manually serialize your payload into `Foundation.Data` and set it as the request body.\nAdditionally you also have to set `Content-Type` header, or otherwise the remote won't be able to understand the content.\n\nAlso the response needs to be decoded, and even if a few decoders are included, e.g. `JSONDecoder`, reading and parsing the `URLResponse` is not intuitive.\n\nEven worse when the response structure differs in case of an error, e.g. instead of\n\n```json\n{\n  \"some\": \"data\"\n}\n```\n\nan error object is returned:\n\n```json\n{\n  \"error\": {\n    \"message\": \"Something went wrong!\"\n  }\n}\n```\n\nThis would require to create combined types such as this one:\n\n```swift\nstruct Response: Decodable {\n    struct ErrorResponse: Decodable {\n        var message: String\n    }\n\n    var some: String?\n    var error: ErrorResponse?\n}\n```\n\nand you would have to use `nil`-checking (probably in combination with the HTTP Status Code) to see which data is present.\n\nCodableRequest simplifies these use cases. The main idea is defining slim `struct` types to build the requests, and serialize the associated responses.\nConfiguration of the request is done using property wrappers, e.g. `@QueryItem`.\n\n## Usage\n\n### Defining the request\n\nCodableRequest includes a couple of types to build your requests. As a first step, create your `Request` type, with an associated `Response`:\n\n```swift\nimport CodableRequest\n\nstruct FooRequest: Request  {\n    typealias Response = EmptyResponse\n}\n```\n\nThe default `Request` type is used for URL requests without any body data.\nIf you want to include payload data, use one of the following ones:\n\n- `PlainRequest`\n- `JSONRequest`\n- `FormURLEncodedRequest`\n\nAll of these expect a `body` instance variable.\nFor `JSONRequest`, `FormURLEncodedRequest` and the type of `body` is generic but needs to implement the `Encodable` protocol.\n\n**Example:**\n\n```swift\nstruct Foo: JSONRequest {\n\n    struct Body: Encodable {}\n    typealias Response = EmptyResponse\n\n    var body: Body\n\n}\n\nstruct Bar: FormURLEncodedRequest {\n\n    struct Body: Encodable {}\n    typealias Response = EmptyResponse\n\n    var body: Body\n\n}\n\n```\n\nFor the `PlainRequest` the body expects a plain `String` content. Optionally you can also overwrite the `encoding` variable with a custom encoding (default is `utf8`).\n\n**Example:**\n\n```swift\nstruct Foo: PlainRequest {\n\n    typealias Response = EmptyResponse\n\n    var body: String\n    var encoding: String.Encoding = .utf16 // default: .utf8\n\n}\n```\n\n#### Setting the request HTTP Method\n\nThe default HTTP method is `GET`, but it can be overwritten by adding an instance property with the property wrapper `@HTTPMethod`:\n\n**Example:**\n\n```swift\nstruct Request: Encodable {\n\n    typealias Response = EmptyResponse\n\n    @HTTPMethod var method\n\n}\n\n// Usage\nvar request = Request()\nrequest.method = .post\n```\n\n**Note:**\n\nAs the property name is ignored, it is possible to have multiple properties with this property wrapper, but only the _last_ one will be used.\n\n#### Setting the request URL path\n\nThe default path `/`, but it can be overwritten by adding an instance property with the property wrapper `Path`:\n\n**Example:**\n\n```swift\nstruct Request: Encodable {\n\n    typealias Response = EmptyResponse\n\n    Path var path\n\n}\n\n// Usage\nlet request = Request(path: \"/some-detail-path\")\n```\n\nAdditionally the request path can contain variables using the mustache syntax, e.g. `/path/with/{variable_name}/inside`.\n\nTo set the variable value, add a new instance property using the `PathParameter` property wrapper.\nBy default the encoder uses the variable name for encoding, but you can also define a custom name:\n\n```swift\nstruct Request: Encodable {\n\n    typealias Response = EmptyResponse\n\n    Path var path = \"/app/{id}/contacts/{cid}\"\n    PathParameter var id: Int\n    PathParameter(name: \"cid\") var contactId: String\n\n}\n\n// Usage\nvar request = Request(id: 123)\nrequest.contactId = \"ABC456\"\n\n// Result:\nhttps://CodableRequest.local/app/123/contacts/ABC456\n```\n\n**Note:**\n\nAs the property name is ignored, it is possible to have multiple properties with this property wrapper, but only the _last_ one will be used.\nAlso you need to require a leading forward slash (`/`) in the path.\n\n#### Adding query items to the URL\n\nMultiple query items can be added by adding them as properties using the property wrapper `@QueryItem`.\n\n**Example:**\n\n```swift\nstruct Request: Encodable {\n\n    typealias Response = EmptyResponse\n\n    @QueryItem\n    var text: String\n\n    @QueryItem(name: \"other_text\")\n    var anotherQuery: String\n\n    @QueryItem\n    var optionalText: String?\n\n}\n\n// Usage\nvar request = Request(text: \"foo\")\nrequest.anotherQuery = \"bar\"\n\n// Result query in URL:\n?text=foo\u0026other_text=bar\n```\n\nIf no custom name is set, the variable name is used. If the query item is optional, and not set (therefore `nil`), it won't be added to the list.\n\nSupported query value types can be found in [`QueryItemValue.swift`](https://github.com/philprime/CodableRequest/blob/main/Sources/CodableRequest/Query/QueryItemValue.swift).\n\n**Note:**\n\nWhen using an `Array` as the query item type, every value in the array is appended using the same `name`.\nThe remote server is then responsible to collect all query items with the same name and merge them into an array.\n\nExample: `[1, 2, 3]` with name `values` becomes `?values=1\u0026values=2\u0026values=3`\n\nAs multiple query items can use the same custom name, they will all be appended to the query.\nThis does not apply to synthesized names, as a Swift type can not have more than one property with the exact same name.\n\n#### Adding Headers to the request\n\nMultiple headers can be set by adding them as properties using the property wrapper `@Header`.\n\n**Example:**\n\n```swift\nstruct Request: Encodable {\n\n    typealias Response = EmptyResponse\n\n    @Header\n    var text: String\n\n    @Header(name: \"other_text\")\n    var anotherQuery: String\n\n    @Header\n    var optionalText: String?\n\n}\n\n// Usage\nvar request = Request(text: \"foo\")\nrequest.anotherQuery = \"bar\"\n\n// Result query in URL:\n?text=foo\u0026other_text=bar\n```\n\nIf no custom name is set, the variable name is used. If the header is optional, and not set (therefore `nil`), it won't be added to the list.\n\nSupported header values types can be found in [`RequestHeaderValue.swift`](https://github.com/philprime/CodableRequest/blob/main/Sources/CodableRequest/Headers/RequestHeaderValue.swift).\n\n**Note:**\n\nAs multiple query items can use the same custom name, the _last_ one will be used.\nThis does not apply to synthesized names, as a Swift type can not have more than one property with the exact same name.\n\n### Defining the response\n\nEvery struct implementing `Request` expects to have an associated `Response` type implementing the `Decodable` protocol.\nIn the examples above the `EmptyResponse` convenience type (which is an empty, decodable type) has been used.\n\nThe response structure will be populated with data from either the response body data or metadata.\n\n#### Parsing the response body\n\nTo parse the response data into a `Decodable` type, add a property with the property wrapper `@ResponseBody\u003cBodyType\u003e` where `BodyType` is the response body type.\n\n**Example:**\n\n```swift\nstruct Request: CodableRequest.Request {\n    struct Response: Decodable {\n        struct Body: Decodable {\n            var value: String\n        }\n\n        @ResponseBody\u003cBody\u003e var body\n    }\n}\n```\n\nTo indicate the decoding system which response data format should be expected, conform your response type to one of the following protocols:\n\n- `PlainDecodable`\n- `JSONDecodable`\n\nFor `JSONDecodable` the type of `body` is generic but needs to implement the `Decodable` protocol.\n\n**Example:**\n\n```swift\nstruct Request: CodableRequest.Request {\n    struct Response: Decodable {\n        struct Body: JSONDecodable {\n            var value: String\n        }\n\n        @ResponseBody\u003cBody\u003e var body\n    }\n}\n```\n\nFor the type `PlainDecodable`, use it directly, as it is an alias for `String`.\n\n**Example:**\n\n```swift\nstruct Request: CodableRequest.Request {\n    struct Response: Decodable {\n        @ResponseBody\u003cPlainDecodable\u003e var body\n    }\n}\n```\n\n#### Response body on error\n\nAs mentioned in [Core Concept](#core-concept) CodableRequest allows defining a body response type when receiving an invalid status code (\u003e=400).\n\nIt's usage is exactly the same as with `@ResponseBody`, but instead you need to use the property wrapper `@ErrorBody`.\nEither the `@ResponseBody` or the `@ErrorBody` is set, never both at the same time.\n\nThe error response body gets set if the response status code is neither a 2XX nor a 3XX status code.\n\n**Example:**\n\n```swift\nstruct Request: CodableRequest.Request {\n    struct Response: Decodable {\n        struct ErrorBody: JSONDecodable {\n            var message: String\n        }\n        @ErrorBody\u003cErrorBody\u003e var errorBody\n    }\n}\n```\n\n#### Custom Encoding Strategy\n\nYou can define a custom `keyEncodingStrategy` and `dateEncodingStrategy` for your `JSONRequest` to determine how the request body's keys and dates are encoded into JSON keys.\nThis can be useful for handling cases where the backend expects keys in a specific format, such as snake\\_case or kebab-case.\n\n**Example:**\n\n```swift\nextension MyRequest: JSONRequest {     \n    static var keyEncodingStrategy: JSONEncoder.KeyEncodingStrategy { .convertToSnakeCase }\n    \n    ...\n}\n```\n\n#### Custom Decoding Strategies\n\nSimilarly, you can specify decoding strategies for handling different date formats or key conventions in JSON responses. \nThese strategies help in parsing complex JSON structures or dates represented in non-standard formats.\n\n**Example:**\n\n```swift\nextension MyRequest.Response: JSONDecodable {\n    static var keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy { .convertFromSnakeCase } \n    static var dateDecodingStrategy: JSONDecoder.DateDecodingStrategy { .formatted(DateFormatter.iso8601Full) } \n}\n```\n\n#### Response parsing strategies\n\nAs the response body might differ depending on various factors, you can control the parsing using \"decoding strategies\".\n\nBy default if you use `ResponseBody` to parse the response body, it will use the `DefaultBodyStrategy` (which expects an HTTP status code 2XX or 3XX).\n\nThe same applies to the `ResponseErrorBody` to parse the response body for a status code of 400 or above, which is using the `DefaultErrorBodyStrategy`.\n\nFor your convenience we added a couple of convenience strategies in `ResponseBody` and `ResponseErrorBody`, you can use with the `ResponseBodyWrapper` and `ErrorBodyWrapper`.\n\nIf you want to implement a custom decoding strategy, all you need to do is define a struct implementing the protocol `ResponseBodyDecodingStrategy` or `ResponseErrorBodyDecodingStrategy`.\n\n**Example:***\n\n```swift\nstruct CustomBodyDecodingStrategy {\n    public static func allowsEmptyContent(for _: Int) -\u003e Bool {\n        false\n    }\n\n    public static func validate(statusCode: Int) -\u003e Bool {\n        // e.g. only decode if the status code is 999\n        statusCode == 999\n    }\n}\n\nstruct Request: CodableRequest.Request {\n    struct Response: Decodable {\n        struct CreatedResponseBody: JSONDecodable {\n            ...\n        }\n        \n        @ResponseBody\u003cCreatedResponseBody\u003e.Status201 var createdBody: CreatedResponseBody\n        \n        struct CustomResponseBody: JSONDecodable {\n            ...\n        }\n        \n        @ResponseBodyWrapper\u003cCustomResponseBody, CustomBodyDecodingStrategy\u003e var customBody\n    }\n}\n```\n\nNote: Due to technical limitations of the `Codable` protocol in Swift, it is currently not possible to have a non-static/dynamic decoding strategy.  \n\n#### Response headers\n\nUse the property wrapper `@ResponseHeader\u003cStrategy\u003e` inside the response type.\n\nIn the moment, the following decoding strategies are implemented:\n\n- `DefaultHeaderStrategy`\n\nConverts the property name into camel-case format (e.g. `Content-Type` becomes `contentType`) and compares case-insensitive (e.g. `Authorization` equals `authorization`)\nThis strategy expects the response header to be set, otherwise an error will be thrown.\n\nResponse from URL requests are always of type `String` and no casting will be performed. Therefore the only valid property type is `String`.\n\n- `DefaultHeaderOptionalStrategy`\n\nSame as `DefaultHeaderStrategy` but won't fail if the header can not be found.\n\n**Example:**\n\n```swift\nstruct Response: Decodable {\n\n    @ResponseHeader\u003cDefaultHeaderStrategy\u003e\n    var authorization: String\n\n    @ResponseHeader\u003cDefaultHeaderStrategy\u003e\n    var contentType: String\n\n    @ResponseHeader\u003cDefaultHeaderStrategyOptional\u003e\n    var optionalValue: String?\n\n}\n```\n\n#### Response Status\n\nThe default HTTP method is `GET`, but it can be overwritten by adding an instance property with the property wrapper `@HTTPMethod`:\n\n**Example:**\n\n```swift\nstruct Response: Decodable {\n\n    @ResponseStatusCode var statusCode\n\n}\n```\n\n**Note:**\n\nMultiple properties can be declared with this property wrapper. All of them will have the value set.\n\n#### Nested Responses\n\nTo support inheritance, which can be especially useful for pagination, use the property wrapper `@NestedResponse` to add nested responses.\n\nWhile decoding the flat HTTP response will be applied recursively to all nested responses, therefore it is possible, that different nested responses access different values of the original HTTP response.\n\n**Example:**\n\n```swift\nstruct PaginatedResponse\u003cNestedRequest: Request\u003e: Decodable {\n\n    /// Header which indicates how many more elements are available\n    @ResponseHeader\u003cDefaultHeaderStrategy\u003e var totalElements\n\n    @NestedResponse var nested: NestedRequest\n}\n\nstruct ListRequest: Request {\n\n    typealias Response = PaginatedResponse\u003cListResponse\u003e\n\n    struct ListResponse: Decodable {\n        // see other examples\n    }\n}\n```\n\n### HTTP API Client\n\nThe easiest way of sending CodableRequest requests, is using the `CodableURLSession` which takes care of encoding requests, and decoding responses.\n\nAll it takes to create a client, is the URL which is used as a base for all requests. Afterwards you can just send the requests, either using Async-Await, Combine publishers, or classic callbacks.\n\nAdditionally the `CodableURLSession` provides the option of setting a `session` provider, which encapsulates the default `URLSession` by a protocol.\nThis allows to create networking clients which can be mocked (perfect for unit testing).\n\n#### Async Await\n\n**Example:**\n\n```swift\nlet url: URL = ...\nlet client = CodableURLSession(baseURL: url)\n\n// ... create request ...\n\ntry {\n    let response = try await client.send(request)\n    // process response\n    print(response)\n} catch {\n    // handle error\n}\n```\n\nYou can also specify queues to send and reveive requests on:\n\n```swift\nlet url: URL = ...\nlet client = CodableURLSession(baseURL: url)\n\n// ... create request ...\n\ntry {\n    let response = try await client.send(request, on: .global(qos: .default), receiveOn: .main)\n    \n    /*  \n        You can also specify queues to send and reveive on  \n            try await client.send(request, on: .global(qos: .default), receiveOn: .main) \n    */\n    \n    // process response\n    print(response)\n} catch {\n    // handle error\n}\n```\n\n#### Combine\n\n**Example:**\n\n```swift\nlet url: URL = ...\nlet client = CodableURLSession(baseURL: url)\n\n// ... create request ...\n\nclient.send(request)\n    .sink(receiveCompletion: { completion in\n        switch completion {\n        case .failure(let error):\n            // handle error\n            break\n        case .finished:\n            break\n        }\n    }, receiveValue: { response in\n        // process response\n        print(response)\n    })\n    .store(in: \u0026cancellables)\n```\n\n#### Callback\n\n**Example:**\n\n```swift\nlet url: URL = ...\nlet client = CodableURLSession(baseURL: url)\n\n// ... create request ...\n\nclient.send(request) { result in\n    switch result {\n    case .failure(let error):\n        // handle error\n        break\n    case .finished(let response):\n        // process response\n        break\n    }\n}\n```\n\n### Cookies\n\nBy default the cookies of requests and responses are handled by the `session` used by the `CodableURLSession`. If you want to explicitly set the request cookies, use `Cookies`, and to access the response cookies use `ResponseCookies`.\n\n**Example:**\n\n```swift\nstruct MyRequest: Request {\n    struct Response: Decodable {\n        // List of HTTPCookie parsed from the `Set-Cookie` headers of the response\n        @ResponseCookies var cookies\n    }\n\n    // List of HTTPCookie to be set in the request as `Cookie` headers\n    @Cookies var cookies\n}\n```\n\n### Encoding \u0026 Decoding\n\nThe `RequestEncoder` is responsible to turn an encodable `Request` into an `URLRequest`. It requires an URL in the initializer, as CodableRequest requests are relative requests.\n\n**Example:**\n\n```swift\n// A request as explained above\nlet request: Request = ...\n\n// Create a request encoder\nlet url = URL(string: \"http://techprimate.com\")\nlet encoder = RequestEncoder(baseURL: url)\n\n// Encode request\nlet urlRequest: URLRequest\ndo {\n    let urlRequest = try encoder.encode(request)\n    // continue with url request\n    ...\n} catch {\n    // Handle error\n    ...\n}\n```\n\nAs its contrarity component, the `RequestDecoder` is responsible to turn a tuple of `(data: Data, response: HTTPURLResponse)` into a given type `Response`.\n\n**Example:**\n\n```swift\n// Data received from the URL session task\nlet response: HTTPURLResponse = ...\nlet data: Data = ...\n\n// Create decoder\nlet decoder = ResponseDecoder()\ndo {\n    let decoded = try decoder.decode(Response.self, from: (data, response)))\n    // continue with decoded response\n    ...\n} catch{\n    // Handle error\n    ...\n}\n```\n\n#### Combine Support\n\n`RequestEncoder` conforms to `TopLevelEncoder` and `RequestDecoder` conforms to `TopLevelDecoder`.\nThis means both encoders can be used in a Combine pipeline.\n\n**Example:**\n\n```swift\nlet request = Request()\nlet session = URLSession.shared\n\nlet url = URL(string: \"https://techprimate.com\")!\nlet encodedRequest = try RequestEncoder(baseURL: url).encode(request)\n\n// Send request using the given URL session provider\nreturn session\n    .dataTaskPublisher(for: encodedRequest)\n    .tryMap { (data: Data, response: URLResponse) in\n        guard let response = response as? HTTPURLResponse else {\n            fatalError(\"handle non HTTP url responses\")\n        }\n        return (data: data, response: response)\n    }\n    .decode(type: Request.Response.self, decoder: ResponseDecoder())\n    .sink(receiveCompletion: { result in\n        // handle result\n    }, receiveValue: { decoded in\n        // do something with decoded response\n    })\n```\n\n# License\n```\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n\n\u003cp\u003eCodableRequest is created and maintained by \u003ca href=\"https://github.com/nzrsky\"\u003eAlex Nazarov\u003c/a\u003e. Based on Postie, created by \u003ca href=\"https://github.com/philprime\"\u003ePhilip Niedertscheider\u003c/a\u003e at \u003ca href=\"https://github.com/kula-app\"\u003ekula.app\u003c/a\u003e and all the amazing \u003ca href=\"https://github.com/nzrsky/CodableRequest/graphs/contributors\"\u003econtributors\u003c/a\u003e.\n\u003c/p\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnzrsky%2Fcodablerequest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnzrsky%2Fcodablerequest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnzrsky%2Fcodablerequest/lists"}