Chris
Chris

Reputation: 431

How to parse JSON Element with Decodable in Swift. I receive errors when doing so

{
"optionChain": {
    "result": [
        {
            "underlyingSymbol": "AAPL",
            "expirationDates": [
                1606435200,
                1655424000,
                1663286400,
                1674172800
            ],
            "strikes": [
                55,
                60,
                65,
                70,
                75,
                80,
                85,
                90,
                95,
                96,
                97,
                98,
                99,
                100,
                101,
                102,
                103,
                104,
                105,
                106,
                107,
                108,
                109,
                110,
                111,
                112,
                113,
                114,
                115,
                116,
                131,
                132,
                133,
                155,
                160,
                165,
                170,
                175
            ],
            "hasMiniOptions": false,
            "quote": {
                "language": "en-US",
                "region": "US",
                "quoteType": "EQUITY",
                "quoteSourceName": "Nasdaq Real Time Price",
                "triggerable": true,
                "currency": "USD",
                "firstTradeDateMilliseconds": 345479400000,
                "priceHint": 2,
                "regularMarketChange": -2.2599945,
                "regularMarketChangePercent": -1.9260223,
                "regularMarketTime": 1606152628,
                "regularMarketPrice": 115.08,
                "regularMarketDayHigh": 117.62,
                "regularMarketDayRange": "113.8 - 117.62",
                "regularMarketDayLow": 113.8,
                "regularMarketVolume": 66403356,
                "regularMarketPreviousClose": 117.34,
                "bid": 114.79,
                "ask": 114.78,
                "bidSize": 9,
                "askSize": 10,
                "fullExchangeName": "NasdaqGS",
                "financialCurrency": "USD",
                "regularMarketOpen": 117.18,
                "averageDailyVolume3Month": 150914918,
                "averageDailyVolume10Day": 78477066,
                "fiftyTwoWeekLowChange": 61.9275,
                "fiftyTwoWeekLowChangePercent": 1.165091,
                "fiftyTwoWeekRange": "53.1525 - 137.98",
                "fiftyTwoWeekHighChange": -22.899994,
                "fiftyTwoWeekHighChangePercent": -0.16596605,
                "fiftyTwoWeekLow": 53.1525,
                "fiftyTwoWeekHigh": 137.98,
                "dividendDate": 1605139200,
                "earningsTimestamp": 1603989000,
                "earningsTimestampStart": 1611658740,
                "earningsTimestampEnd": 1612180800,
                "trailingAnnualDividendRate": 0.795,
                "trailingPE": 35.085365,
                "trailingAnnualDividendYield": 0.0067751836,
                "epsTrailingTwelveMonths": 3.28,
                "epsForward": 4.33,
                "epsCurrentYear": 3.96,
                "priceEpsCurrentYear": 29.060606,
                "sharesOutstanding": 17102499840,
                "bookValue": 3.849,
                "fiftyDayAverage": 116.774574,
                "fiftyDayAverageChange": -1.6945724,
                "fiftyDayAverageChangePercent": -0.014511485,
                "twoHundredDayAverage": 104.00763,
                "twoHundredDayAverageChange": 11.072372,
                "twoHundredDayAverageChangePercent": 0.10645731,
                "marketCap": 1956567187456,
                "forwardPE": 26.577368,
                "priceToBook": 29.898676,
                "sourceInterval": 15,
                "exchangeDataDelayedBy": 0,
                "tradeable": false,
                "exchange": "NMS",
                "shortName": "Apple Inc.",
                "longName": "Apple Inc.",
                "marketState": "REGULAR",
                "messageBoardId": "finmb_24937",
                "exchangeTimezoneName": "America/New_York",
                "exchangeTimezoneShortName": "EST",
                "gmtOffSetMilliseconds": -18000000,
                "market": "us_market",
                "esgPopulated": false,
                "displayName": "Apple",
                "symbol": "AAPL"
            },
            "options": [
                {
                    "expirationDate": 1606435200,
                    "hasMiniOptions": false,
                    "calls": [
                        {
                            "contractSymbol": "AAPL201127C00165000",
                            "strike": 165,
                            "currency": "USD",
                            "lastPrice": 0.01,
                            "change": 0,
                            "percentChange": 0,
                            "volume": 1,
                            "openInterest": 156,
                            "bid": 0,
                            "ask": 0.01,
                            "contractSize": "REGULAR",
                            "expiration": 1606435200,
                            "lastTradeDate": 1605731100,
                            "impliedVolatility": 1.000005,
                            "inTheMoney": false
                        },
                        {
                            "contractSymbol": "AAPL201127C00170000",
                            "strike": 170,
                            "currency": "USD",
                            "lastPrice": 0.01,
                            "change": 0,
                            "percentChange": 0,
                            "volume": 11,
                            "openInterest": 353,
                            "bid": 0,
                            "ask": 0.01,
                            "contractSize": "REGULAR",
                            "expiration": 1606435200,
                            "lastTradeDate": 1605731115,
                            "impliedVolatility": 1.0625046875000002,
                            "inTheMoney": false
                        },
                        {
                            "contractSymbol": "AAPL201127C00175000",
                            "strike": 175,
                            "currency": "USD",
                            "lastPrice": 0.01,
                            "change": 0,
                            "percentChange": 0,
                            "volume": 5,
                            "openInterest": 259,
                            "bid": 0,
                            "ask": 0.01,
                            "contractSize": "REGULAR",
                            "expiration": 1606435200,
                            "lastTradeDate": 1606150652,
                            "impliedVolatility": 1.15625421875,
                            "inTheMoney": false
                        }
                    ],
                    "puts": [
                        {
                            "contractSymbol": "AAPL201127P00134000",
                            "strike": 134,
                            "currency": "USD",
                            "lastPrice": 14.2,
                            "change": 0,
                            "percentChange": 0,
                            "volume": 4,
                            "openInterest": 133,
                            "bid": 19.1,
                            "ask": 19.35,
                            "contractSize": "REGULAR",
                            "expiration": 1606435200,
                            "lastTradeDate": 1605632020,
                            "impliedVolatility": 0.831056376953125,
                            "inTheMoney": true
                        },
                        {
                            "contractSymbol": "AAPL201127P00135000",
                            "strike": 135,
                            "currency": "USD",
                            "lastPrice": 21.05,
                            "change": 3.869999,
                            "percentChange": 22.526186,
                            "volume": 38,
                            "openInterest": 258,
                            "bid": 20.35,
                            "ask": 20.5,
                            "contractSize": "REGULAR",
                            "expiration": 1606435200,
                            "lastTradeDate": 1606148156,
                            "impliedVolatility": 0.96679720703125,
                            "inTheMoney": true
                        },
                        {
                            "contractSymbol": "AAPL201127P00138000",
                            "strike": 138,
                            "currency": "USD",
                            "lastPrice": 19.41,
                            "change": 0,
                            "percentChange": 0,
                            "openInterest": 1,
                            "bid": 23.1,
                            "ask": 23.25,
                            "contractSize": "REGULAR",
                            "expiration": 1606435200,
                            "lastTradeDate": 1605819053,
                            "impliedVolatility": 0.91992267578125,
                            "inTheMoney": true
                        },
                        {
                            "contractSymbol": "AAPL201127P00140000",
                            "strike": 140,
                            "currency": "USD",
                            "lastPrice": 21.19,
                            "change": 0,
                            "percentChange": 0,
                            "volume": 24,
                            "openInterest": 53,
                            "bid": 25.2,
                            "ask": 25.35,
                            "contractSize": "REGULAR",
                            "expiration": 1606435200,
                            "lastTradeDate": 1605818102,
                            "impliedVolatility": 1.0429735351562504,
                            "inTheMoney": true
                        },
                        {
                            "contractSymbol": "AAPL201127P00145000",
                            "strike": 145,
                            "currency": "USD",
                            "lastPrice": 26.85,
                            "change": 0,
                            "percentChange": 0,
                            "volume": 1,
                            "openInterest": 55,
                            "bid": 30.2,
                            "ask": 30.35,
                            "contractSize": "REGULAR",
                            "expiration": 1606435200,
                            "lastTradeDate": 1605892788,
                            "impliedVolatility": 1.185550947265625,
                            "inTheMoney": true
                        },
                        {
                            "contractSymbol": "AAPL201127P00175000",
                            "strike": 175,
                            "currency": "USD",
                            "lastPrice": 57.13,
                            "change": 0,
                            "percentChange": 0,
                            "volume": 2,
                            "openInterest": 2,
                            "bid": 60.15,
                            "ask": 60.25,
                            "contractSize": "REGULAR",
                            "expiration": 1606435200,
                            "lastTradeDate": 1605798274,
                            "impliedVolatility": 1.822266513671875,
                            "inTheMoney": true
                        }
                    ]
                }
            ]
        }
    ],
    "error": null
}}

Above is the API JSON response from my calls. Now below is the decodable written in swift.

 struct Something: Decodable
{
    let optionChain: OptionChain
    let error: String
}

struct OptionChain: Decodable
{
    let result: [ResultElement]
}

struct ResultElement: Decodable
{
    let underlyingSymbol: String
    let expirationDates: [Int]
    let strikes: [Int]
    let hasMiniOptions: Bool
    let quote: [quoteElement]
    let options: [optionsElement]
}

struct quoteElement: Decodable
{
    let language: String
    let region: String
    let quoteType: String
    let quoteSourceName: String
    let triggerable: Bool
    let currency: String
    let firstTradeDateMilliseconds: Int
    let priceHint: Int
    let regularMarketChange: Int
    let regularMarketChangePercent: Int
    let regularMarketTime: Int
    let regularMarketPrice: Int
    let regularMarketDayHigh: Int
    let regularMarketDayRange: String
    let regularMarketDayLow: Int
    let regularMarketVolume: Int
    let regularMarketPreviousClose: Int
    let bid: Int
    let ask: Int
    let bidSize: Int
    let askSize: Int
    let fullExchangeName: String
    let financialCurrency: String
    let regularMarketOpen: Int
    let averageDailyVolume3Month: Int
    let averageDailyVolume10Day: Int
    let fiftyTwoWeekLowChange: Int
    let fiftyTwoWeekLowChangePercent: Int
    let fiftyTwoWeekRange: String
    let fiftyTwoWeekHighChange: Int
    let fiftyTwoWeekHighChangePercent: Int
    let fiftyTwoWeekLow: Int
    let fiftyTwoWeekHigh: Int
    let dividendDate: Int
    let earningsTimestamp: Int
    let earningsTimestampStart: Int
    let earningsTimestampEnd: Int
    let trailingAnnualDividendRate: Int
    let trailingPE: Int
    let trailingAnnualDividendYield: Int
    let epsTrailingTwelveMonths: Int
    let epsForward: Int
    let epsCurrentYear: Int
    let priceEpsCurrentYear: Int
    let sharesOutstanding: Int
    let bookValue: Int
    let fiftyDayAverage: Int
    let fiftyDayAverageChange: Int
    let fiftyDayAverageChangePercent: Int
    let twoHundredDayAverage: Int
    let twoHundredDayAverageChange: Int
    let twoHundredDayAverageChangePercent: Int
    let marketCap: Int
    let forwardPE: Int
    let priceToBook: Int
    let sourceInterval: Int
    let exchangeDataDelayedBy: Int
    let tradeable: Bool
    let exchange: String
    let shortName: String
    let longName: String
    let marketState: String
    let messageBoardId: String
    let exchangeTimezoneName: String
    let exchangeTimezoneShortName: String
    let gmtOffSetMilliseconds: Int
    let market: String
    let esgPopulated: Bool
    let displayName: String
    let symbol: String
}

struct optionsElement: Decodable
{
    let expirationDate: Int
    let hasMiniOptions: Bool
    let calls: [callPutElement]
    let puts: [callPutElement]
}

struct callPutElement: Decodable
{
    let contractSymbol: String
    let strike: Int
    let currency: String
    let lastPrice: Int
    let change: Int
    let percentChange: Int
    let volume: Int
    let openInterest: Int
    let bid: Int
    let ask: Int
    let contractSize: String
    let expiration: Int
    let lastTradeDate: Int
    let impliedVolatility: Int
    let inTheMoney: Bool
}

I call those decodables from this code below:

  let request = NSMutableURLRequest(url: NSURL(string: urlTicker)! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "GET"
    request.allHTTPHeaderFields = headers

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
        if (error != nil)
        {
            print(error)
        }
        else
        {
            let httpResponse = response as? HTTPURLResponse
            
            do
            {
                let jsonString = "{...}"

                let jsonData = jsonString.data(using: .utf8)!

                let decoder = JSONDecoder()
                let something = try decoder.decode(Something.self, from: jsonData)

                print(something.optionChain.result.map { $0.underlyingSymbol })
                
                //let myJSON = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any]
                //let likes = myJSON!["optionChain"] as? Array<Dictionary<String, Any>>

            }
            catch
            {
                print("JSONSerialization error:", error)
            }
            
            //print(httpResponse)
            //print(myJSON["strikes"] as! String)
        }
    })

    dataTask.resume()

I get into the catch statement and the error is:

SONSerialization error: dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "No string key for value in object around character 1." UserInfo={NSDebugDescription=No string key for value in object around character 1.})))

Am I using decodeables wrong?

Upvotes: 0

Views: 177

Answers (1)

Leo Dabus
Leo Dabus

Reputation: 236568

The only issue I had to take care when decoding your data was to set the date decoding strategy. Just set your dateDecodingStrategy to .secondsSince1970. try like this:


struct Root: Codable {
    let optionChain: OptionChain
}

struct OptionChain: Codable {
    let result: [Result]
}

struct Result: Codable {
    let underlyingSymbol: String
    let expirationDates: [Date]
    let strikes: [Int]
    let hasMiniOptions: Bool
    let quote: Quote
    let options: [Option]
}

struct Option: Codable {
    let expirationDate: Date
    let hasMiniOptions: Bool
    let calls: [Call]
    let puts: [Call]
}

struct Call: Codable {
    let contractSymbol: String
    let strike: Int
    let currency: String
    let lastPrice: Double
    let change, percentChange: Double
    let volume: Int?
    let openInterest: Int
    let bid, ask: Double
    let contractSize: String
    let expiration, lastTradeDate: Date
    let impliedVolatility: Double
    let inTheMoney: Bool
}

struct Quote: Codable {
    let language,region, quoteType, quoteSourceName: String
    let triggerable: Bool
    let currency: String
    let firstTradeDateMilliseconds, priceHint: Int
    let regularMarketChange, regularMarketChangePercent: Double
    let regularMarketTime: Int
    let regularMarketPrice, regularMarketDayHigh: Double
    let regularMarketDayRange: String
    let regularMarketDayLow: Double
    let regularMarketVolume: Int
    let regularMarketPreviousClose, bid, ask: Double
    let bidSize, askSize: Int
    let fullExchangeName, financialCurrency: String
    let regularMarketOpen: Double
    let averageDailyVolume3Month, averageDailyVolume10Day: Int
    let fiftyTwoWeekLowChange, fiftyTwoWeekLowChangePercent: Double
    let fiftyTwoWeekRange: String
    let fiftyTwoWeekHighChange, fiftyTwoWeekHighChangePercent: Double
    let fiftyTwoWeekLow, fiftyTwoWeekHigh: Double
    let dividendDate, earningsTimestamp, earningsTimestampStart, earningsTimestampEnd: Date
    let trailingAnnualDividendRate, trailingPE, trailingAnnualDividendYield, epsTrailingTwelveMonths, epsForward, epsCurrentYear, priceEpsCurrentYear: Double
    let sharesOutstanding: Int
    let bookValue, fiftyDayAverage, fiftyDayAverageChange, fiftyDayAverageChangePercent, twoHundredDayAverage, twoHundredDayAverageChange, twoHundredDayAverageChangePercent: Double
    let marketCap: Int
    let forwardPE, priceToBook: Double
    let sourceInterval, exchangeDataDelayedBy: Int
    let tradeable: Bool
    let exchange, shortName, longName, marketState, messageBoardId, exchangeTimezoneName, exchangeTimezoneShortName: String
    let gmtOffSetMilliseconds: Int
    let market: String
    let esgPopulated: Bool
    let displayName, symbol: String
}

playground testing

do {
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .secondsSince1970
    let root = try decoder.decode(Root.self, from: .init(json.utf8))
    print(root)
} catch {
    print(error)
}

This will print

Root(optionChain: __lldb_expr_184.OptionChain(result: [__lldb_expr_184.Result(underlyingSymbol: "AAPL", expirationDates: [2020-11-27 00:00:00 +0000, 2022-06-17 00:00:00 +0000, 2022-09-16 00:00:00 +0000, 2023-01-20 00:00:00 +0000], strikes: [55, 60, 65, 70, 75, 80, 85, 90, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 131, 132, 133, 155, 160, 165, 170, 175], hasMiniOptions: false, quote: __lldb_expr_184.Quote(language: "en-US", region: "US", quoteType: "EQUITY", quoteSourceName: "Nasdaq Real Time Price", triggerable: true, currency: "USD", firstTradeDateMilliseconds: 345479400000, priceHint: 2, regularMarketChange: -2.2599945, regularMarketChangePercent: -1.9260223, regularMarketTime: 1606152628, regularMarketPrice: 115.08, regularMarketDayHigh: 117.62, regularMarketDayRange: "113.8 - 117.62", regularMarketDayLow: 113.8, regularMarketVolume: 66403356, regularMarketPreviousClose: 117.34, bid: 114.79, ask: 114.78, bidSize: 9, askSize: 10, fullExchangeName: "NasdaqGS", financialCurrency: "USD", regularMarketOpen: 117.18, averageDailyVolume3Month: 150914918, averageDailyVolume10Day: 78477066, fiftyTwoWeekLowChange: 61.9275, fiftyTwoWeekLowChangePercent: 1.165091, fiftyTwoWeekRange: "53.1525 - 137.98", fiftyTwoWeekHighChange: -22.899994, fiftyTwoWeekHighChangePercent: -0.16596605, fiftyTwoWeekLow: 53.1525, fiftyTwoWeekHigh: 137.98, dividendDate: 2020-11-12 00:00:00 +0000, earningsTimestamp: 2020-10-29 16:30:00 +0000, earningsTimestampStart: 2021-01-26 10:59:00 +0000, earningsTimestampEnd: 2021-02-01 12:00:00 +0000, trailingAnnualDividendRate: 0.795, trailingPE: 35.085365, trailingAnnualDividendYield: 0.0067751836, epsTrailingTwelveMonths: 3.28, epsForward: 4.33, epsCurrentYear: 3.96, priceEpsCurrentYear: 29.060606, sharesOutstanding: 17102499840, bookValue: 3.849, fiftyDayAverage: 116.774574, fiftyDayAverageChange: -1.6945724, fiftyDayAverageChangePercent: -0.014511485, twoHundredDayAverage: 104.00763, twoHundredDayAverageChange: 11.072372, twoHundredDayAverageChangePercent: 0.10645731, marketCap: 1956567187456, forwardPE: 26.577368, priceToBook: 29.898676, sourceInterval: 15, exchangeDataDelayedBy: 0, tradeable: false, exchange: "NMS", shortName: "Apple Inc.", longName: "Apple Inc.", marketState: "REGULAR", messageBoardId: "finmb_24937", exchangeTimezoneName: "America/New_York", exchangeTimezoneShortName: "EST", gmtOffSetMilliseconds: -18000000, market: "us_market", esgPopulated: false, displayName: "Apple", symbol: "AAPL"), options: [__lldb_expr_184.Option(expirationDate: 2020-11-27 00:00:00 +0000, hasMiniOptions: false, calls: [__lldb_expr_184.Call(contractSymbol: "AAPL201127C00165000", strike: 165, currency: "USD", lastPrice: 0.01, change: 0.0, percentChange: 0.0, volume: Optional(1), openInterest: 156, bid: 0.0, ask: 0.01, contractSize: "REGULAR", expiration: 2020-11-27 00:00:00 +0000, lastTradeDate: 2020-11-18 20:25:00 +0000, impliedVolatility: 1.000005, inTheMoney: false), __lldb_expr_184.Call(contractSymbol: "AAPL201127C00170000", strike: 170, currency: "USD", lastPrice: 0.01, change: 0.0, percentChange: 0.0, volume: Optional(11), openInterest: 353, bid: 0.0, ask: 0.01, contractSize: "REGULAR", expiration: 2020-11-27 00:00:00 +0000, lastTradeDate: 2020-11-18 20:25:15 +0000, impliedVolatility: 1.0625046875000002, inTheMoney: false), __lldb_expr_184.Call(contractSymbol: "AAPL201127C00175000", strike: 175, currency: "USD", lastPrice: 0.01, change: 0.0, percentChange: 0.0, volume: Optional(5), openInterest: 259, bid: 0.0, ask: 0.01, contractSize: "REGULAR", expiration: 2020-11-27 00:00:00 +0000, lastTradeDate: 2020-11-23 16:57:32 +0000, impliedVolatility: 1.15625421875, inTheMoney: false)], puts: [__lldb_expr_184.Call(contractSymbol: "AAPL201127P00134000", strike: 134, currency: "USD", lastPrice: 14.2, change: 0.0, percentChange: 0.0, volume: Optional(4), openInterest: 133, bid: 19.1, ask: 19.35, contractSize: "REGULAR", expiration: 2020-11-27 00:00:00 +0000, lastTradeDate: 2020-11-17 16:53:40 +0000, impliedVolatility: 0.831056376953125, inTheMoney: true), __lldb_expr_184.Call(contractSymbol: "AAPL201127P00135000", strike: 135, currency: "USD", lastPrice: 21.05, change: 3.869999, percentChange: 22.526186, volume: Optional(38), openInterest: 258, bid: 20.35, ask: 20.5, contractSize: "REGULAR", expiration: 2020-11-27 00:00:00 +0000, lastTradeDate: 2020-11-23 16:15:56 +0000, impliedVolatility: 0.96679720703125, inTheMoney: true), __lldb_expr_184.Call(contractSymbol: "AAPL201127P00138000", strike: 138, currency: "USD", lastPrice: 19.41, change: 0.0, percentChange: 0.0, volume: nil, openInterest: 1, bid: 23.1, ask: 23.25, contractSize: "REGULAR", expiration: 2020-11-27 00:00:00 +0000, lastTradeDate: 2020-11-19 20:50:53 +0000, impliedVolatility: 0.91992267578125, inTheMoney: true), __lldb_expr_184.Call(contractSymbol: "AAPL201127P00140000", strike: 140, currency: "USD", lastPrice: 21.19, change: 0.0, percentChange: 0.0, volume: Optional(24), openInterest: 53, bid: 25.2, ask: 25.35, contractSize: "REGULAR", expiration: 2020-11-27 00:00:00 +0000, lastTradeDate: 2020-11-19 20:35:02 +0000, impliedVolatility: 1.0429735351562504, inTheMoney: true), __lldb_expr_184.Call(contractSymbol: "AAPL201127P00145000", strike: 145, currency: "USD", lastPrice: 26.85, change: 0.0, percentChange: 0.0, volume: Optional(1), openInterest: 55, bid: 30.2, ask: 30.35, contractSize: "REGULAR", expiration: 2020-11-27 00:00:00 +0000, lastTradeDate: 2020-11-20 17:19:48 +0000, impliedVolatility: 1.185550947265625, inTheMoney: true), __lldb_expr_184.Call(contractSymbol: "AAPL201127P00175000", strike: 175, currency: "USD", lastPrice: 57.13, change: 0.0, percentChange: 0.0, volume: Optional(2), openInterest: 2, bid: 60.15, ask: 60.25, contractSize: "REGULAR", expiration: 2020-11-27 00:00:00 +0000, lastTradeDate: 2020-11-19 15:04:34 +0000, impliedVolatility: 1.822266513671875, inTheMoney: true)])])]))

Upvotes: 2

Related Questions