Postie - The Next-Level HTTP API Client using Combine

Overview

Postie

Postie - The Next-Level HTTP API Client using Combine

CI Documentation codecov

Postie is a pure Swift library for building URLRequests using property wrappers.

Core Concept

The networking layer of Foundation (and with Combine) is already quite advanced. Using URLRequest you can set many different configuration values, e.g. the HTTP Method or Headers.

Unfortunately you still need to manually serialize your payload into Foundation.Data and set it as the request body. Additionally you also have to set Content-Type header, or otherwise the remote won't be able to understand the content.

Also 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.

Even worse when the response structure differs in case of an error, e.g. instead of

{ 
    "some": "data"
}

an error object is returned:

{
    "error":  {
        "message": "Something went wrong!"
    }
}

This would require to create combined types such as this one:

struct Response: Decodable {
    struct ErrorResponse: Decodable {
        var message: String
    }

    var some: String?
    var error: ErrorResponse?
}

and you would have to use nil-checking (probably in combination with the HTTP Status Code) to see which data is present.

Postie simplifies these use cases. The main idea is defining slim struct types to build the requests, and serialize the associated responses. Configuration of the request is done using property wrappers, e.g. @QueryItem.

Usage

Defining the request

Postie includes a couple of types to build your requests. As a first step, create your Request type, with an associated Response:

import Postie

struct FooRequest: Request  {
    typealias Response = EmptyResponse
}

The default Request type is used for URL requests without any body data. If you want to include payload data, use one of the following ones:

  • PlainRequest
  • JSONRequest
  • FormURLEncodedRequest

All of these expect a body instance variable. For JSONRequest and FormURLEncodedRequest the type of body is generic but needs to implement the Encodable protocol.

Example:

struct Foo: JSONRequest {

    struct Body: Encodable {}
    typealias Response = EmptyResponse

    var body: Body
    
}

struct Bar: FormURLEncodedRequest {

    struct Body: Encodable {}
    typealias Response = EmptyResponse

    var body: Body
    
}

For the PlainRequest the body expects a plain String content. Optionally you can also overwrite the encoding variable with a custom encoding (default is utf8).

Example:

struct Foo: PlainRequest {

    typealias Response = EmptyResponse

    var body: String
    var encoding: String.Encoding = .utf16 // default: .utf8
    
}

Setting the request HTTP Method

The default HTTP method is GET, but it can be overwritten by adding an instance property with the property wrapper @RequestHTTPMethod:

Example:

struct Request: Encodable {

    typealias Response = EmptyResponse

    @RequestHTTPMethod var method

}

// Usage
var request = Request()
request.method = .post

Note:

As the property name is ignored, it is possible to have multiple properties with this property wrapper, but only the last one will be used.

Setting the request URL path

The default path /, but it can be overwritten by adding an instance property with the property wrapper @RequestPath:

Example:

struct Request: Encodable {

    typealias Response = EmptyResponse

    @RequestPath var path

}

// Usage
let request = Request(path: "/some-detail-path")

Additionally the request path can contain variables using the mustache syntax, e.g. /path/with/{variable_name}/inside.

To set the variable value, add a new instance property using the @RequestPathParameter property wrapper. By default the encoder uses the variable name for encoding, but you can also define a custom name:

struct Request: Encodable {

    typealias Response = EmptyResponse

    @RequestPath var path = "/app/{id}/contacts/{cid}"
    @RequestPathParameter var id: Int
    @RequestPathParameter(name: "cid") var contactId: String

}

// Usage
var request = Request(id: 123)
request.contactId = "ABC456"

// Result: 
https://postie.local/app/123/contacts/ABC456

Note:

As the property name is ignored, it is possible to have multiple properties with this property wrapper, but only the last one will be used. Also you need to require a leading forward slash (/) in the path.

Adding query items to the URL

Multiple query items can be added by adding them as properties using the property wrapper @QueryItem.

Example:

struct Request: Encodable {

    typealias Response = EmptyResponse

    @QueryItem
    var text: String

    @QueryItem(name: "other_text")
    var anotherQuery: String

    @QueryItem
    var optionalText: String?

}

// Usage
var request = Request(text: "foo")
request.anotherQuery = "bar"

// Result query in URL:
?text=foo&other_text=bar

If 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.

Supported query value types can be found in QueryItemValue.swift.

Note:

When using an Array as the query item type, every value in the array is appended using the same name. The remote server is then responsible to collect all query items with the same name and merge them into an array.

Example: [1, 2, 3] with name values becomes ?values=1&values=2&values=3

As multiple query items can use the same custom name, they will all be appended to the query. This does not apply to synthesized names, as a Swift type can not have more than one property with the exact same name.

Adding Headers to the request

Multiple headers can be set by adding them as properties using the property wrapper @RequestHeader.

Example:

struct Request: Encodable {

    typealias Response = EmptyResponse

    @RequestHeader
    var text: String

    @RequestHeader(name: "other_text")
    var anotherQuery: String

    @RequestHeader
    var optionalText: String?

}

// Usage
var request = Request(text: "foo")
request.anotherQuery = "bar"

// Result query in URL:
?text=foo&other_text=bar

If 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.

Supported header values types can be found in RequestHeaderValue.swift.

Note:

As multiple query items can use the same custom name, the last one will be used. This does not apply to synthesized names, as a Swift type can not have more than one property with the exact same name.

Defining the response

Every struct implementing Request expects to have an associated Response type implementing the Decodable protocol. In the examples above the EmptyResponse convenience type (which is an empty, decodable type) has been used.

The response structure will be populated with data from either the response body data or metadata.

Parsing the response body

To parse the response data into a Decodable type, add a property with the property wrapper @ResponseBody where BodyType is the response body type.

Example:

struct Request: Postie.Request {
    struct Response: Decodable {
        struct Body: Decodable {
            var value: String
        }

        @ResponseBody<Body> var body
    }
}

To indicate the decoding system which response data format should be expected, conform your response type to one of the following protocols:

  • PlainDecodable
  • JSONDecodable
  • FormURLEncodedDecodable

For JSONDecodable and FormURLEncodedDecodable the type of body is generic but needs to implement the Decodable protocol.

Example:

struct Request: Postie.Request {
    struct Response: Decodable {
        struct Body: JSONDecodable {
            var value: String
        }

        @ResponseBody<Body> var body
    }
}

struct Request: Postie.Request {
    struct Response: Decodable {
        struct Body: FormURLEncodedDecodable {
            var value: String
        }

        @ResponseBody<Body> var body
    }
}

For the type PlainDecodable, use it directly, as it is an alias for String.

Example:

struct Request: Postie.Request {
    struct Response: Decodable {
        @ResponseBody<PlainDecodable> var body
    }
}

Response body on error

As mentioned in Core Concept Postie allows defining a body response type when receiving an invalid status code (>=400).

It's usage is exactly the same as with @ResponseBody, but instead you need to use the property wrapper @ResponseErrorBody. Either the @ResponseBody or the @ResponseErrorBody is set, never both at the same time.

The error response body gets set if the response status code is neither a 2XX nor a 3XX status code.

Example:

struct Request: Postie.Request {
    struct Response: Decodable {
        struct ErrorBody: JSONDecodable {
            var message: String
        }
        @ResponseErrorBody<ErrorBody> var errorBody
    }
}

Response headers

Use the property wrapper @ResponseHeader inside the response type.

In the moment, the following decoding strategies are implemented:

  • DefaultStategy

Converts the property name into camel-case format (e.g. Content-Type becomes contentType) and compares case-insensitive (e.g. Authorization equals authorization) This strategy expects the response header to be set, otherwise an error will be thrown.

Response from URL requests are always of type String and no casting will be performed. Therefore the only valid property type is String.

  • DefaultOptionalStategy

Same as DefaultStrategy but won't fail if the header can not be found.

Example:

struct Response: Decodable {

    @ResponseHeader<DefaultStrategy>
    var authorization: String

    @ResponseHeader<DefaultStrategy>
    var contentType: String

    @ResponseHeader<DefaultStrategyOptional>
    var optionalValue: String?

}

Response Status

The default HTTP method is GET, but it can be overwritten by adding an instance property with the property wrapper @RequestHTTPMethod:

Example:

struct Response: Decodable {

    @ResponseStatusCode var statusCode

}

Note:

Multiple properties can be declared with this property wrapper. All of them will have the value set.

HTTP API Client

The easiest way of sending Postie requests, is using the HTTPAPIClient which takes care of encoding requests, and decoding responses.

All 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, using the Combine publishers.

Additionally the HTTPAPIClient provides the option of setting a session provider, which encapsulates the default URLSession by a protocol. This allows to create networking clients which can be mocked (perfect for unit testing).

Example:

let url: URL = ...
let client = HTTPAPIClient(baseURL: url)

// ... create request ...

client.send(request)
    .sink(receiveCompletion: { completion in
        switch completion {
        case .failure(let error):
            // handle error
            break
        case .finished:
            break
        }
    }, receiveValue: { response in
        // process response
        print(response)
    })
    .store(in: &cancellables)
//

Encoding & Decoding

The RequestEncoder is responsible to turn an encodable Request into an URLRequest. It requires an URL in the initializer, as Postie requests are relative requests.

Example:

// A request as explained above
let request: Request = ...

// Create a request encoder
let url = URL(string: "http://techprimate.com")
let encoder = RequestEncoder(baseURL: url)

// Encode request
let urlRequest: URLRequest
do {
    let urlRequest = try encoder.encode(request)
    // continue with url request
    ...
} catch {
    // Handle error
    ...
}

As its contrarity component, the RequestDecoder is responsible to turn a tuple of (data: Data, response: HTTPURLResponse) into a given type Response.

Example:

// Data received from the URL session task
let response: HTTPURLResponse = ...
let data: Data = ...

// Create decoder
let decoder = ResponseDecoder()
do {
    let decoded = try decoder.decode(Response.self, from: (data, response))) 
    // continue with decoded response
    ...
} catch{
    // Handle error
    ...
}

Combine Support

RequestEncoder conforms to TopLevelEncoder and RequestDecoder conforms to TopLevelDecoder. This means both encoders can be used in a Combine pipeline.

Example:

let request = Request()
let session = URLSession.shared

let url = URL(string: "https://techprimate.com")!
let encodedRequest = try RequestEncoder(baseURL: url).encode(request)

// Send request using the given URL session provider
return session
    .dataTaskPublisher(for: encodedRequest)
    .tryMap { (data: Data, response: URLResponse) in
        guard let response = response as? HTTPURLResponse else {
            fatalError("handle non HTTP url responses")
        }
        return (data: data, response: response)
    }
    .decode(type: Request.Response.self, decoder: ResponseDecoder())
    .sink(receiveCompletion: { result in
        // handle result
    }, receiveValue: { decoded in
        // do something with decoded response
    })
Comments
  • Proposition to add support for empty responses

    Proposition to add support for empty responses

    This feature would let the client decide wether or not to handle some empty responses (e.g. some endpoint sometimes returning data, some other time nothing at all).

    opened by Pomanks 21
  • fixed issue with resolvedPath sometimes causing range out of bounds issue

    fixed issue with resolvedPath sometimes causing range out of bounds issue

    this happened when the resolvedPath variable was mutated (inside the method) and another loop round was needed but the count was not valid anymore (e.g. path.count != resolvedPath.length)

    opened by Pomanks 5
  • Update dependency MaxDesiatov/XMLCoder to from:

    Update dependency MaxDesiatov/XMLCoder to from: "0.14.0"

    Mend Renovate

    This PR contains the following updates:

    | Package | Update | Change | |---|---|---| | MaxDesiatov/XMLCoder | minor | from: "0.13.1" -> from: "0.14.0" |


    Release Notes

    MaxDesiatov/XMLCoder

    v0.14.0

    Compare Source

    What's Changed

    New Contributors

    Full Changelog: https://github.com/CoreOffice/XMLCoder/compare/0.13.1...0.14.0


    Configuration

    📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

    🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

    Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    🔕 Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, click this checkbox.

    This PR has been generated by Mend Renovate. View repository job log here.

    opened by renovate[bot] 1
  • added support for integer conversion from DefaultHeaderStrategyOptional

    added support for integer conversion from DefaultHeaderStrategyOptional

    this relies on the same principle found in DefaultHeaderStrategy

    added some test cases

    Note: this feature might be helpful when retrieving page/page count/items count/… in header and converting them directly to a more compatible and useful type than a String.

    opened by Pomanks 1
  • CVE-2022-24440 (High) detected in cocoapods-downloader-1.5.1.gem - autoclosed

    CVE-2022-24440 (High) detected in cocoapods-downloader-1.5.1.gem - autoclosed

    CVE-2022-24440 - High Severity Vulnerability

    Vulnerable Library - cocoapods-downloader-1.5.1.gem

    Library home page: https://rubygems.org/gems/cocoapods-downloader-1.5.1.gem

    Path to dependency file: /Gemfile.lock

    Path to vulnerable library: /var/lib/gems/2.5.0/cache/cocoapods-downloader-1.5.1.gem

    Dependency Hierarchy:

    • jazzy-0.14.1.gem (Root Library)
      • cocoapods-1.11.2.gem
        • :x: cocoapods-downloader-1.5.1.gem (Vulnerable Library)

    Found in base branch: main

    Vulnerability Details

    The package cocoapods-downloader before 1.6.0, from 1.6.2 and before 1.6.3 are vulnerable to Command Injection via git argument injection. When calling the Pod::Downloader.preprocess_options function and using git, both the git and branch parameters are passed to the git ls-remote subcommand in a way that additional flags can be set. The additional flags can be used to perform a command injection.

    Publish Date: 2022-04-01

    URL: CVE-2022-24440

    CVSS 3 Score Details (8.1)

    Base Score Metrics:

    • Exploitability Metrics:
      • Attack Vector: Network
      • Attack Complexity: High
      • Privileges Required: None
      • User Interaction: None
      • Scope: Unchanged
    • Impact Metrics:
      • Confidentiality Impact: High
      • Integrity Impact: High
      • Availability Impact: High

    For more information on CVSS3 Scores, click here.

    Suggested Fix

    Type: Upgrade version

    Origin: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24440

    Release Date: 2022-04-01

    Fix Resolution: cocoapods-downloader - 1.6.0,1.6.3


    Step up your Open Source Security Game with WhiteSource here

    security vulnerability 
    opened by mend-bolt-for-github[bot] 1
  • CVE-2022-21223 (High) detected in cocoapods-downloader-1.5.1.gem - autoclosed

    CVE-2022-21223 (High) detected in cocoapods-downloader-1.5.1.gem - autoclosed

    CVE-2022-21223 - High Severity Vulnerability

    Vulnerable Library - cocoapods-downloader-1.5.1.gem

    Library home page: https://rubygems.org/gems/cocoapods-downloader-1.5.1.gem

    Path to dependency file: /Gemfile.lock

    Path to vulnerable library: /var/lib/gems/2.5.0/cache/cocoapods-downloader-1.5.1.gem

    Dependency Hierarchy:

    • jazzy-0.14.1.gem (Root Library)
      • cocoapods-1.11.2.gem
        • :x: cocoapods-downloader-1.5.1.gem (Vulnerable Library)

    Found in base branch: main

    Vulnerability Details

    The package cocoapods-downloader before 1.6.2 are vulnerable to Command Injection via hg argument injection. When calling the download function (when using hg), the url (and/or revision, tag, branch) is passed to the hg clone command in a way that additional flags can be set. The additional flags can be used to perform a command injection.

    Publish Date: 2022-04-01

    URL: CVE-2022-21223

    CVSS 3 Score Details (8.1)

    Base Score Metrics:

    • Exploitability Metrics:
      • Attack Vector: Network
      • Attack Complexity: High
      • Privileges Required: None
      • User Interaction: None
      • Scope: Unchanged
    • Impact Metrics:
      • Confidentiality Impact: High
      • Integrity Impact: High
      • Availability Impact: High

    For more information on CVSS3 Scores, click here.

    Suggested Fix

    Type: Upgrade version

    Origin: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21223

    Release Date: 2022-04-01

    Fix Resolution: cocoapods-downloader - 1.6.2


    Step up your Open Source Security Game with WhiteSource here

    security vulnerability 
    opened by mend-bolt-for-github[bot] 1
  • CVE-2021-32740 (High) detected in addressable-2.7.0.gem - autoclosed

    CVE-2021-32740 (High) detected in addressable-2.7.0.gem - autoclosed

    CVE-2021-32740 - High Severity Vulnerability

    Vulnerable Library - addressable-2.7.0.gem

    Addressable is an alternative implementation to the URI implementation that is part of Ruby's standard library. It is flexible, offers heuristic parsing, and additionally provides extensive support for IRIs and URI templates.

    Library home page: https://rubygems.org/gems/addressable-2.7.0.gem

    Dependency Hierarchy:

    • jazzy-0.13.7.gem (Root Library)
      • cocoapods-1.10.1.gem
        • :x: addressable-2.7.0.gem (Vulnerable Library)

    Found in HEAD commit: d650232187aa473f2ebe712121df73b0ecfde0a3

    Found in base branch: main

    Vulnerability Details

    Addressable is an alternative implementation to the URI implementation that is part of Ruby's standard library. An uncontrolled resource consumption vulnerability exists after version 2.3.0 through version 2.7.0. Within the URI template implementation in Addressable, a maliciously crafted template may result in uncontrolled resource consumption, leading to denial of service when matched against a URI. In typical usage, templates would not normally be read from untrusted user input, but nonetheless, no previous security advisory for Addressable has cautioned against doing this. Users of the parsing capabilities in Addressable but not the URI template capabilities are unaffected. The vulnerability is patched in version 2.8.0. As a workaround, only create Template objects from trusted sources that have been validated not to produce catastrophic backtracking.

    Publish Date: 2021-07-06

    URL: CVE-2021-32740

    CVSS 3 Score Details (7.5)

    Base Score Metrics:

    • Exploitability Metrics:
      • Attack Vector: Network
      • Attack Complexity: Low
      • Privileges Required: None
      • User Interaction: None
      • Scope: Unchanged
    • Impact Metrics:
      • Confidentiality Impact: None
      • Integrity Impact: None
      • Availability Impact: High

    For more information on CVSS3 Scores, click here.

    Suggested Fix

    Type: Upgrade version

    Origin: https://github.com/sporkmonger/addressable/security/advisories/GHSA-jxhc-q857-3j6g

    Release Date: 2021-07-06

    Fix Resolution: addressable - 2.8.0


    Step up your Open Source Security Game with WhiteSource here

    security vulnerability 
    opened by mend-bolt-for-github[bot] 1
  • Update actions/cache action to v3

    Update actions/cache action to v3

    WhiteSource Renovate

    This PR contains the following updates:

    | Package | Type | Update | Change | |---|---|---|---| | actions/cache | action | major | v2 -> v3 |


    Release Notes

    actions/cache

    v3

    Compare Source


    Configuration

    📅 Schedule: At any time (no schedule defined).

    🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

    Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    🔕 Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, click this checkbox.

    This PR has been generated by WhiteSource Renovate. View repository job log here.

    opened by renovate[bot] 0
  • Update actions/checkout action to v3

    Update actions/checkout action to v3

    WhiteSource Renovate

    This PR contains the following updates:

    | Package | Type | Update | Change | |---|---|---|---| | actions/checkout | action | major | v2 -> v3 |


    Release Notes

    actions/checkout

    v3

    Compare Source


    Configuration

    📅 Schedule: At any time (no schedule defined).

    🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

    Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    🔕 Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, click this checkbox.

    This PR has been generated by WhiteSource Renovate. View repository job log here.

    opened by renovate[bot] 0
  • Update dependency MaxDesiatov/XMLCoder to from:

    Update dependency MaxDesiatov/XMLCoder to from: "0.13.1" - autoclosed

    WhiteSource Renovate

    This PR contains the following updates:

    | Package | Update | Change | |---|---|---| | MaxDesiatov/XMLCoder | minor | from: "0.1.3" -> from: "0.13.1" |


    Release Notes

    MaxDesiatov/XMLCoder

    v0.13.1

    Compare Source

    This is a bugfix release that fixes an edge case with the use of trimValueWhitespaces configuration on XMLDecoder, and adds official Windows support for users of Swift 5.5. Many thanks to @​MartinP7r for multiple contributions to this release!

    Closed issues:

    • Encoding an Attribute doesn't work anymore (#​231)
    • How to "skip" certain XML tags / element in a TCX file (#​227)
    • Encode element with empty key, no elements, and attributes (#​224)

    Merged pull requests:

    v0.13.0

    Compare Source

    This release adds two new features and a bugfix.

    Namely:

    • removeWhitespaceElements boolean flag on XMLDecoder allows removing elements that have purely whitespace content.
    • convertFromUppercase case on KeyDecodingStrategy allows converting ALL_CAPS_SNAKE_CASE to camelCase.
    • an edge case in intrinsic key value decoding has been fixed.

    Many thanks to @​huwr, @​kneekey23, and @​wooj2 for their contributions!

    Closed issues:

    • Decoding special whitespace characters (#​219)
    • Help with mix of attributes and elements (#​212)

    Merged pull requests:

    v0.12.0

    Compare Source

    This release adds a few new features. Namely:

    • New charactersEscapedInAttributes and charactersEscapedInElements properties on XMLEncoder that allow customizing how certain characters are escaped.
    • You can now override the implementation of TopLevelEncoder Combine protocol conformance when subclassing XMLEncoder.
    • New prettyPrintIndentation property on XMLEncoder, which can take XMLEncoder.PrettyPrintIndentation values such as .tabs(1) or .spaces(2).

    Thanks to Kenta Kubo for the contribution!

    Closed issues:

    • How to decode <itunes:episode> tags (#​201)
    • Fail to build in Xcode 12 beta (#​196)
    • Changing the root node name ? (#​191)
    • " in XML element may not always be escaping (#​187)
    • &#&#8203;10; in XML attributes (#​185)
    • " and &quot; are not decoded equally (#​184)
    • Use 2 spaces instead of 4 when .prettyPrinted (#​183)
    • (Help using) How to decode this XML? (#​180)

    Merged pull requests:

    v0.11.1

    Compare Source

    This release fixes an issue, where non-string values used CDATA encoding. Thanks to @​ksoftllc for reporting it!

    Closed issues:

    • Non-string values are being encoded as CData (#​178)
    • How to encode as an empty element (#​177)

    Merged pull requests:

    v0.11.0

    Compare Source

    This is a bugfix and feature release, which fixes an issue with CDATA decoding and adds TopLevelEncoder conformance to XMLEncoder. New rootAttributes argument has been added to the encode function on XMLEncoder that allows adding attributes on root elements without adding them to your model types. Thanks to @​portellaa, @​Kirow and others for their contributions and bug reports!

    Closed issues:

    • CDATA Decoding not working (#​168)
    • Decode special XML Structure (#​156)
    • Root level attributes don't get encoded back to attribute when converting back to XML file from Plist (#​127)
    • Bad access error when running on device (#​100)

    Merged pull requests:

    v0.10.0

    Compare Source

    This is a bugfix release, which improves encoding and decoding of enums with associated values (also known as "choice coding") with the XMLChoiceCodingKey protocol. This release is also tested on Xcode 11.4 and Swift 5.2.1 on Linux. A few breaking changes were introduced, which were needed to simplify and improve internals of the library. Please refer to the corresponding section below for more details. Thanks to @​bwetherfield and @​ultramiraculous for their contributions!

    Breaking changes:

    This change was needed to accommodate for multiple edges cases with how arrays of empty elements and empty strings are decoded.

    The value intrinsic now only accepts the empty string key "", as the previous "value" key caused naming collisions with attributes and elemenents that had the same name.

    Closed issues:

    • Bundle identifier in wrong format (#​164)
    • Can inheritance be implemented? (#​159)
    • EXC_BAD_ACCESS when running tests (#​153)
    • EXC_BAD_ACCESS on XCode 11.2 and iOS13.2 (#​150)
    • Date formatting on 24h region with display set to 12h (#​148)
    • Decoding containers with (potentially)-empty elements (#​123)

    Merged pull requests:

    v0.9.0

    Compare Source

    This release fixes a few bugs with Float type parsing and Swift 5.1 support on Linux. It also adds a helper extension to improve compatibility with Combine and adds a few tests to confirm that a few edges cases are working well. Thanks to @​bwetherfield, @​DJBen, @​jsbean, @​mxcl, @​marcblanchet and @​sharplet for bug reports and pull requests!

    Implemented enhancements:

    Fixed bugs:

    • Value with copyright symbol © has its preceding whitespace trimmed off even trimValueWhitespaces is set to false #​141
    • Float vs Float64=Double not parsing 3.14 #​130

    Closed issues:

    • TrackPoint position parameter is ignored #​125
    • TCX file need an XML root node #​124
    • [Swift 5.1] Import FoundationXML rather than Foundation #​121

    Merged pull requests:

    v0.8.0

    Compare Source

    This release adds support for decoding and encoding ordered sequences of different elements as enums with associated values. In addition, XMLCoder now supports Linux. Many thanks to @​jsbean, @​bwetherfield and @​drewag for implementing this!

    Breaking changes:

    • Fixed typo in XMLDecoder property: errorContextLenght has been renamed to errorContextLength in #​114.

    Closed issues:

    • XML with autoclosed tags #​116
    • Arrays of enums #​91
    • Array of enums with associated values #​25

    Merged pull requests:

    v0.7.0

    Compare Source

    This release changes the behavior of attributes coding: now order of XML attributes is fully preserved. One of the benefits is that it improves unit testing for users of XMLCoder, which allows testing against specific encoded attributes without accounting for their randomized order. Also a small coding style fix is included. In addition, XMLCoder now uses Azure Pipelines instead of Travis for CI with great improvements to overall CI stability, speed, and parallel builds. Thanks to Andrés Cecilia Luque and Jay Hickey for the contributions!

    Merged pull requests:

    v0.6.0

    Compare Source

    An improvement release that introduces convertFromKebabCase and convertToKebabCase key decoding strategies. There were a few changes that aren't visible to end-users: the way that keys and values are stored internally has changed and a few more tests added. Thanks to Andrés Cecilia Luque and Vincent Esche for the contributions!

    Merged pull requests:

    v0.5.1

    Compare Source

    Bugfix release that restores decoding of empty sequences, which became broken in 0.5.0.

    Merged pull requests:

    v0.5.0

    Compare Source

    A small improvement release tagged early to resolve blocking issues in CoreXLSX.

    Notable changes:

    • Empty value strings are no longer decoded as nil when a String is expected, but are decoded as empty strings, which represents the actual value.
    • trimValueWhitespaces property was added on XMLDecoder, which allows overriding the default behaviour, where starting and trailing whitespaces are trimmed from string values.

    Closed issues:

    • Trimmed whitespace on decoding String #​94

    Merged pull requests:

    v0.4.1

    Compare Source

    A bugfix release removing unused Xcode project scheme to improve build time for Carthage users.

    Notable changes:

    v0.4.0

    Compare Source

    This is a release with plenty of new features that allow you to parse many more XML variations than previously. Compatibility with Xcode 10.2 and Swift 5.0 is also improved. A huge thank you to @​JoeMatt and @​regexident for their contributions, to @​hodovani for maintaining the project, and to @​Inukinator, @​qmoya, @​Ma-He, @​khoogheem and @​thecb4 for reporting issues during development!

    Notable changes:

    • Ordered encoding: this was one of the most requested changes and it's finally here! 🎉 Now both keyed and unkeyed elements are encoded in the exactly same order that was used in original containers. This is applicable to both compiler-generated encoding implementations (just reorder properties or cases in your CodingKeys enum if you have it) and manually implemented func encode(to: Encoder).
    • Stripping namespace prefix: now if your coding key string values contain an XML namespace prefix (e.g. prefix h in <h:td>Apples</h:td>), you can set shouldProcessNamespaces property to true on your XMLDecoder instance for the prefix to be stripped before decoding keys in your Decodable types.
    • Previously it was possible to customize encoding with NodeEncodingStrategy, but no such type existed for decoding. A corresponding NodeDecodingStrategy type was added with nodeDecodingStrategy property on XMLDecoder.
    • Thanks to the previous change, XMLCoder now provides two helper protocols that allow you to easily customize whether nodes are encoded and decoded as attributes or elements for conforming types: DynamicNodeEncoding and DynamicNodeDecoding.
    • Previously if you needed to decode or encode an XML element with both attributes and values, this was impossible to do with XMLCoder. Now with the addition of coding key value intrinsic, this is as easy as adding one coding key with a specific string raw value ("value" or empty string "" if you already have an XML attribute named "value").

    Closed issues:

    • Crash: Range invalid bounds in XMLStackParser.swift #​83
    • Document DynamicNodeEncoding and attributed intrinsic #​80
    • Fix nested attributed intrinsic #​78
    • nodeEncodingStrategy #​49
    • XmlEncoder: ordering of elements #​17
    • Can’t reach an XML value #​12

    Merged pull requests:

    v0.3.1

    Compare Source

    A bugfix release that adds missing CFBundleVersion in generated framework's Info.plist (#​72 reported by @​stonedauwg).

    Changes:

    v0.3.0

    Compare Source

    A maintenance release focused on fixing bugs, improving error reporting and overall internal architecture of the library. For this release we've started tracking test coverage and were able to increase it from 11.8% to 75.6%. 🎉 Thanks to @​hodovani and @​regexident for their work on improving test coverage in this release.

    Additions:

    You can now set errorContextLength: UInt property on XMLDecoder instance, which will make it add a snippet of XML of at most this length from parser state when a parsing error occurs. This change was provided by @​hodovani and can greatly help with attempts to parse invalid XML, where previously only a line and column number were reported.

    Deprecations:

    NodeEncodingStrategies was renamed to NodeEncodingStrategy for consistency. NodeEncodingStrategies is still available as a deprecated typealias, which will be removed in future versions. Thanks to @​regexident for cleaning this up and providing many more changes in this release that make XMLCoder better and easier to use.

    Changes:

    v0.2.1

    Compare Source


    Configuration

    📅 Schedule: At any time (no schedule defined).

    🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

    Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    🔕 Ignore: Close this PR and you won't be reminded about this update again.


    • [x] If you want to rebase/retry this PR, click this checkbox.

    This PR has been generated by WhiteSource Renovate. View repository job log here.

    opened by renovate[bot] 0
  • Configure Renovate

    Configure Renovate

    WhiteSource Renovate

    Welcome to Renovate! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin.

    🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged.


    Detected Package Files

    • Gemfile (bundler)
    • .github/workflows/documentation.yml (github-actions)
    • .github/workflows/publish_release.yml (github-actions)
    • .github/workflows/swift.yml (github-actions)
    • Package.swift (swift)

    Configuration Summary

    Based on the default config's presets, Renovate will:

    • Start dependency updates only once this onboarding PR is merged
    • Enable Renovate Dependency Dashboard creation
    • If semantic commits detected, use semantic commit type fix for dependencies and chore for all others
    • Ignore node_modules, bower_components, vendor and various test/tests directories
    • Autodetect whether to pin dependencies or maintain ranges
    • Rate limit PR creation to a maximum of two per hour
    • Limit to maximum 10 open PRs at any time
    • Group known monorepo packages together
    • Use curated list of recommended non-monorepo package groupings
    • Fix some problems with very old Maven commons versions
    • Ignore spring cloud 1.x releases
    • Ignore http4s digest-based 1.x milestones
    • Use node versioning for @types/node
    • Limit concurrent requests to reduce load on Repology servers until we can fix this properly, see issue 10133

    🔡 Would you like to change the way Renovate is upgrading your dependencies? Simply edit the renovate.json in this branch with your custom config and the list of Pull Requests in the "What to Expect" section below will be updated the next time Renovate runs.


    What to Expect

    With your current configuration, Renovate will create 1 Pull Request:

    Update dependency MaxDesiatov/XMLCoder to from: "0.13.1"
    • Schedule: ["at any time"]
    • Branch name: renovate/maxdesiatov-xmlcoder-0.x
    • Merge into: main
    • Upgrade MaxDesiatov/XMLCoder to f30119af03996939cc4f54e0bf0dda9f88a84da5

    ❓ Got questions? Check out Renovate's Docs, particularly the Getting Started section. If you need any further assistance then you can also request help here.


    This PR has been generated by WhiteSource Renovate. View repository job log here.

    opened by renovate[bot] 0
  • Update dependency MaxDesiatov/XMLCoder to from:

    Update dependency MaxDesiatov/XMLCoder to from: "0.15.0"

    Mend Renovate

    This PR contains the following updates:

    | Package | Update | Change | |---|---|---| | MaxDesiatov/XMLCoder | minor | from: "0.14.0" -> from: "0.15.0" |


    Release Notes

    MaxDesiatov/XMLCoder

    v0.15.0

    Compare Source

    What's Changed

    New Maintainer

    Full Changelog: https://github.com/CoreOffice/XMLCoder/compare/0.14.0...0.15.0


    Configuration

    📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

    🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

    Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    🔕 Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, check this box

    This PR has been generated by Mend Renovate. View repository job log here.

    opened by renovate[bot] 0
  • Dependency Dashboard

    Dependency Dashboard

    This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

    Open

    These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

    Detected dependencies

    bundler
    Gemfile
    • jazzy undefined
    github-actions
    .github/workflows/documentation.yml
    • actions/checkout v3
    • actions/cache v3
    .github/workflows/publish_release.yml
    • actions/checkout v3
    .github/workflows/swift.yml
    • actions/checkout v3
    • actions/checkout v3
    • norio-nomura/action-swiftlint 3.2.1
    swift
    Package.swift
    • MaxDesiatov/XMLCoder from: "0.14.0"

    • [ ] Check this box to trigger a request for Renovate to run again on this repository
    opened by renovate[bot] 0
Releases(v0.0.13)
Owner
kula
the app to make an app
kula
A type-safe, high-level networking solution for Swift apps

What Type-safe network calls made easy Netswift offers an easy way to perform network calls in a structured and type-safe way. Why Networking in Swift

Dorian Grolaux 23 Apr 27, 2022
YTKNetwork is a high level request util based on AFNetworking.

YTKNetwork What YTKNetwork is a high level request util based on AFNetworking. It's developed by the iOS Team of YuanTiKu. It provides a High Level AP

猿辅导技术团队 6.5k Jan 6, 2023
Next Generation of ShadowsocksX

ShadowsocksX-NG Download Next Generation of ShadowsocksX Why a new implementation? It's hard to maintain the original implementation as there is too m

shadowsocks 30.9k Jan 4, 2023
A barebones Swift HTTP client with automatic JSON response parsing.

HTTP Client A barebones Swift HTTP client with automatic JSON response parsing. Installation Add HTTP Client as a dependency through Xcode or directly

Joe Masilotti 30 Oct 11, 2022
A simple GCD based HTTP client and server, written in 'pure' Swift

SwiftyHTTP Note: I'm probably not going to update this any further - If you need a Swift networking toolset for the server side, consider: Macro.swift

Always Right Institute 116 Aug 6, 2022
📡 RealHTTP is a lightweight yet powerful client-side HTTP library.

RealHTTP RealHTTP is a lightweight yet powerful client-side HTTP library. Our goal is make an easy to use and effortless http client for Swift. Featur

Immobiliare Labs 233 Jan 7, 2023
The HTTP library used by the Spotify iOS client

Authentication and back-off logic is a pain, let's do it once and forget about it! This is a library that allows you to centralise this logic and forg

Spotify 625 Nov 20, 2022
HTTPClient - HTTP Client With Swift

HTTPClient Ex. Search Repository import HTTPClient let url: URL = .init(string:

zunda 1 Jul 20, 2022
Cross-platform JsonRPC client implementation with HTTP and WebSocket support

JsonRPC.swift Cross-platform JsonRPC client implementation with HTTP and WebSocket support Getting started Installation Package Manager Add the follow

Tesseract 5 Oct 19, 2022
An awesome Swift HTTP library to rapidly create communication layers with API endpoints

An awesome Swift HTTP library to rapidly create communication layers with API endpoints

Binary Birds 69 Nov 28, 2022
Simple iOS app in Swift to show AQI for some cities using websocket using Combine + MVVM

AQI Simple iOS app in Swift to show AQI for some cities using websocket using Combine + MVVM This app follows MVVM This app uses combine framework The

Amey Vikkram Tiwari 2 Nov 6, 2022
A web API client in Swift built using Async/Await

Get A modern web API client in Swift built using Async/Await and Actors. let cli

Alexander Grebenyuk 745 Jan 3, 2023
Twitter-Client - A twitter client that allow users to view tweets on their iphone

Project 3 - Twitter Client Name of your app is a basic twitter app to read your

null 0 Feb 7, 2022
Swift HTTP server using the pre-fork worker model

Curassow Curassow is a Swift Nest HTTP Server. It uses the pre-fork worker model and it's similar to Python's Gunicorn and Ruby's Unicorn. It exposes

Kyle Fuller Archive 397 Oct 30, 2022
FlyingFox - a lightweight HTTP server built using Swift Concurrency

Usage Credits Introduction FlyingFox is a lightweight HTTP server built using Swift Concurrency. The server uses non blocking BSD sockets, handling ea

Simon Whitty 262 Dec 24, 2022
Alamofire Network Layer written in swift 5 using the protocol oriented, combine, UIKit, MVVM.

CoreAPI-iOS This project Contains Alamofire Network layer Based on Protocol Oriented Concept and Combine Framework. It is created with UIKit, Alamofir

Mehran Kamalifard 27 Nov 11, 2022
An iOS library to route API paths to objects on client side with request, mapping, routing and auth layers

WANetworkRouting Developed and Maintained by ipodishima Founder & CTO at Wasappli Inc. Sponsored by Wisembly A routing library to fetch objects from a

null 10 Nov 20, 2022
An unofficial supported Swift client library for accessing News API.

An unofficial supported Swift client library for accessing News API.

Fumiya Yamanaka 9 Oct 1, 2022
The official iOS client library for api.video

api.video iOS client api.video is the video infrastructure for product builders.

api.video 8 Dec 2, 2022