This is a listing of raw data returned from different cases of network requests and model decoding in Swift, with emphasis on error cases. Useful for the purpose of mocking error responses.
The Star Wars API is used as reference.
Case | Data | Response | Network error | Decoding |
---|---|---|---|---|
1) Successful | Some | 200 | nil | Ok |
2) Non-existing host | nil | nil | NSURLErrorDomain (-1003) |
N/A |
3) Non-existing resource | Some | 404 | nil | dataCorrupted |
4) Non-existing query | Some | 200(a) | nil | typeMismatch (a) |
5) Corrupted data | Some | 200 | nil | dataCorrupted |
6) Model mismatch | Some | 200 | nil | keyNotFound |
7) Offline mode | nil | nil | NSURLErrorDomain (-1009) |
N/A |
(a) Some APIs return 404 when a non-existing query is used, giving keyNotFound
as error when decoding. The sample StarWars API returns a valid response, just ignoring the non-existing query.
Sample output of playground follows.
Data: :
Optional("{\"people\":\"https://swapi.co/api/people/\",\"planets\":\"https://swapi.co/api/planets/\",\"films\":\"https://swapi.co/api/films/\",\"species\":\"https://swapi.co/api/species/\",\"vehicles\":\"https://swapi.co/api/vehicles/\",\"starships\":\"https://swapi.co/api/starships/\"}")
Response:
<NSHTTPURLResponse: 0x6000000338c0> { URL: https://swapi.co/api/ } { Status Code: 200, Headers {
"Content-Encoding" = (
gzip
);
"Content-Type" = (
"application/json"
);
Date = (
"Wed, 16 May 2018 12:09:45 GMT"
);
Etag = (
"W/\"c1df070b0509ebefe72e85d721f40bf0\""
);
Server = (
cloudflare
);
Vary = (
"Accept, Cookie"
);
Via = (
"1.1 vegur"
);
allow = (
"GET, HEAD, OPTIONS"
);
"cf-ray" = (
"41bdbcbb7f7263df-FRA"
);
"expect-ct" = (
"max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""
);
"x-frame-options" = (
SAMEORIGIN
);
} }
Network error: none
Decoded model:
API(films: https://swapi.co/api/films/, people: https://swapi.co/api/people/, planets: https://swapi.co/api/planets/, species: https://swapi.co/api/species/, starships: https://swapi.co/api/starships/, vehicles: https://swapi.co/api/vehicles/)
Data: none
Response: none
Network Error :
Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo={NSUnderlyingError=0x600001055d80 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "(null)" UserInfo={_kCFStreamErrorCodeKey=8, _kCFStreamErrorDomainKey=12}}, NSErrorFailingURLStringKey=https://nonexisting.co/api/, NSErrorFailingURLKey=https://nonexisting.co/api/, _kCFStreamErrorDomainKey=12, _kCFStreamErrorCodeKey=8, NSLocalizedDescription=A server with the specified hostname could not be found.}
Data:
Optional("<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n<meta charset=\"utf-8\">\n<title>\n SWAPI - The Star Wars API\n </title>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<link rel=\"stylesheet\" href=\"//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css\">\n<link href=\"/static/css/bootstrap.css\" rel=\"stylesheet\">\n<link href=\"/static/css/custom.css\" rel=\"stylesheet\">\n<link rel=\"shortcut icon\" href=\"/static/favicon.ico\">\n</style>\n<script src=\"//code.jquery.com/jquery-2.1.0.min.js\" type=\"12b2974bbe4f5b3be4eb1eb3-\"></script>\n<script src=\"//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js\" type=\"12b2974bbe4f5b3be4eb1eb3-\"></script>\n</script>\n</head>\n<body>\n<nav class=\"navbar navbar-default\" role=\"navigation\">\n<div class=\"container-fluid\">\n<div class=\"navbar-header\">\n<button
(abridged for brevity) Response:
<NSHTTPURLResponse: 0x60400002eec0> { URL: https://swapi.co/api/chewbacca/ } { Status Code: 404, Headers {
"Content-Encoding" = (
gzip
);
"Content-Type" = (
"text/html; charset=utf-8"
);
Date = (
"Wed, 16 May 2018 12:54:30 GMT"
);
Server = (
cloudflare
);
Via = (
"1.1 vegur"
);
"cf-ray" = (
"41bdfe484ca263df-FRA"
);
"expect-ct" = (
"max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""
);
"x-frame-options" = (
SAMEORIGIN
);
} }
Network error: none
Decoding error:
dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})))
Data:
Optional("{\"count\":7,\"next\":null,\"previous\":null,\"results\":[{\"title\":\"A New Hope\",\"episode_id\":4,\"opening_crawl\":\"It is a period of civil war.\\r\\nRebel spaceships, striking\\r\\nfrom a hidden base, have won\\r\\ntheir first victory against\\r\\nthe evil Galactic Empire.\\r\\n\\r\\nDuring the battle, Rebel\\r\\nspies managed to steal secret\\r\\nplans to the Empire\'s\\r\\nultimate weapon, the DEATH\\r\\nSTAR, an armored space\\r\\nstation with enough power\\r\\nto destroy an entire planet.\\r\\n\\r\\nPursued by the Empire\'s\\r\\nsinister agents, Princess\\r\\nLeia races home aboard her\\r\\nstarship, custodian of the\\r\
(abridged for brevity)
Response:
<NSHTTPURLResponse: 0x6000002237a0> { URL: https://swapi.co/api/films/?nonexisting=query } { Status Code: 200, Headers {
"Content-Encoding" = (
gzip
);
"Content-Type" = (
"application/json"
);
Date = (
"Thu, 17 May 2018 09:37:31 GMT"
);
Etag = (
"W/\"a6f57b83572279727b3a9208d0653a82\""
);
Server = (
cloudflare
);
Vary = (
"Accept, Cookie"
);
Via = (
"1.1 vegur"
);
allow = (
"GET, HEAD, OPTIONS"
);
"cf-ray" = (
"41c51b159f046403-FRA"
);
"expect-ct" = (
"max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""
);
"x-frame-options" = (
SAMEORIGIN
);
} }
Network error: none
Decoding error:
typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "releaseDate", intValue: nil)], debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil))
Data: (overriden by playground for sample of corrupted data)
Response:
<NSHTTPURLResponse: 0x600000026fc0> { URL: https://swapi.co/api/ } { Status Code: 200, Headers {
"Content-Encoding" = (
gzip
);
"Content-Type" = (
"application/json"
);
Date = (
"Wed, 16 May 2018 12:54:34 GMT"
);
Etag = (
"W/\"c1df070b0509ebefe72e85d721f40bf0\""
);
Server = (
cloudflare
);
Vary = (
"Accept, Cookie"
);
Via = (
"1.1 vegur"
);
allow = (
"GET, HEAD, OPTIONS"
);
"cf-ray" = (
"41bdfe5c684a6415-FRA"
);
"expect-ct" = (
"max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""
);
"x-frame-options" = (
SAMEORIGIN
);
} }
Network error: none
Decoding error:
dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})))
Data:
Optional("{\"people\":\"https://swapi.co/api/people/\",\"planets\":\"https://swapi.co/api/planets/\",\"films\":\"https://swapi.co/api/films/\",\"species\":\"https://swapi.co/api/species/\",\"vehicles\":\"https://swapi.co/api/vehicles/\",\"starships\":\"https://swapi.co/api/starships/\"}")
Response:
<NSHTTPURLResponse: 0x60400002e3e0> { URL: https://swapi.co/api/ } { Status Code: 200, Headers {
"Content-Encoding" = (
gzip
);
"Content-Type" = (
"application/json"
);
Date = (
"Wed, 16 May 2018 12:54:35 GMT"
);
Etag = (
"W/\"c1df070b0509ebefe72e85d721f40bf0\""
);
Server = (
cloudflare
);
Vary = (
"Accept, Cookie"
);
Via = (
"1.1 vegur"
);
allow = (
"GET, HEAD, OPTIONS"
);
"cf-ray" = (
"41bdfe63fc5863af-FRA"
);
"expect-ct" = (
"max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\""
);
"x-frame-options" = (
SAMEORIGIN
);
} }
Network error: none
Decoding error:
keyNotFound(CodingKeys(stringValue: "count", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"count\", intValue: nil) (\"count\").", underlyingError: nil))
Data: none
Response: none
Network Error :
Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={NSUnderlyingError=0x60400005fbf0 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}, NSErrorFailingURLStringKey=https://swapi.co/api/, NSErrorFailingURLKey=https://swapi.co/api/, _kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=50, NSLocalizedDescription=The Internet connection appears to be offline.}