summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadVPN/REST/RESTCoding.swift
blob: 8a5356e3bcddf15e879cd4767db740e8c22a209c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//
//  RESTCoding.swift
//  RESTCoding
//
//  Created by pronebird on 27/07/2021.
//  Copyright © 2021 Mullvad VPN AB. All rights reserved.
//

import Foundation

extension REST {
    enum Coding {}
}

extension REST.Coding {
    /// Returns a JSON encoder used by REST API.
    static func makeJSONEncoder() -> JSONEncoder {
        let encoder = JSONEncoder()
        encoder.keyEncodingStrategy = .convertToSnakeCase
        encoder.dataEncodingStrategy = .base64
        encoder.dateEncodingStrategy = .iso8601
        return encoder
    }

    /// Returns a JSON decoder used by REST API.
    static func makeJSONDecoder() -> JSONDecoder {
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        decoder.dataDecodingStrategy = .base64

        let iso8601Formatter = ISO8601DateFormatter()

        // Setup additional formatter to account for fractional seconds returned
        // by some of the API calls.
        lazy var iso8601WithSubSecondsFormatter: ISO8601DateFormatter = {
            let formatter = ISO8601DateFormatter()
            formatter.formatOptions.insert(.withFractionalSeconds)
            return formatter
        }()

        decoder.dateDecodingStrategy = .custom({ decoder in
            let container = try decoder.singleValueContainer()
            let value = try container.decode(String.self)

            let date = iso8601Formatter.date(from: value) ??
                iso8601WithSubSecondsFormatter.date(from: value)

            switch date {
            case .some(let parsedDate):
                return parsedDate

            case .none:
                throw DecodingError.dataCorruptedError(
                    in: container,
                    debugDescription: "Expected date string to be RFC3339 or ISO8601-formatted."
                )
            }
        })

        return decoder
    }
}