Swift
swift4

[iOS][Swift 4] CodableでJSONのパース (2)

[iOS][Swift 4] CodableでJSONのパースの続きです。

JSONのキーとパースするクラスのプロパティ名が異なる場合のパース方法です。
基本的には、Using JSON with Custom Typesに書かれている内容です。

以下のようなJSONをパースする場合
GitHub Gists - List all public gists

let json = """
[
  {
    "url": "https://api.github.com/gists/aa5a315d61ae9438b18d",
    "forks_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/forks",
    "commits_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/commits",
    "id": "aa5a315d61ae9438b18d",
    "node_id": "MDQ6R2lzdGFhNWEzMTVkNjFhZTk0MzhiMThk",
    "description": "description of gist",
    "public": true,
    "owner": {
      "login": "octocat",
      "id": 1,
      "node_id": "MDQ6VXNlcjE=",
      "avatar_url": "https://github.com/images/error/octocat_happy.gif",
      "gravatar_id": "",
      "url": "https://api.github.com/users/octocat",
      "html_url": "https://github.com/octocat",
      "followers_url": "https://api.github.com/users/octocat/followers",
      "following_url": "https://api.github.com/users/octocat/following/other_user",
      "gists_url": "https://api.github.com/users/octocat/gists/gist_id",
      "starred_url": "https://api.github.com/users/octocat/starred/owner/repo",
      "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
      "organizations_url": "https://api.github.com/users/octocat/orgs",
      "repos_url": "https://api.github.com/users/octocat/repos",
      "events_url": "https://api.github.com/users/octocat/events/privacy",
      "received_events_url": "https://api.github.com/users/octocat/received_events",
      "type": "User",
      "site_admin": false
    },
    "user": null,
    "files": {
      "ring.erl": {
        "size": 932,
        "raw_url": "https://gist.githubusercontent.com/raw/365370/8c4d2d43d178df44f4c03a7f2ac0ff512853564e/ring.erl",
        "type": "text/plain",
        "truncated": false,
        "language": "Erlang"
      }
    },
    "truncated": false,
    "comments": 0,
    "comments_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/comments/",
    "html_url": "https://gist.github.com/aa5a315d61ae9438b18d",
    "git_pull_url": "https://gist.github.com/aa5a315d61ae9438b18d.git",
    "git_push_url": "https://gist.github.com/aa5a315d61ae9438b18d.git",
    "created_at": "2010-04-14T02:15:15Z",
    "updated_at": "2011-06-20T11:34:15Z"
  }
]
""".data(using: .utf8)!

プロパティ名と対応するキーをCodingKeysにて指定する。

struct GitHubGistsContentFile: Codable {
    let size: Int
    let rawUrl: URL
    let type: String
    let truncated: Bool
    let language: String

    private enum CodingKeys: String, CodingKey {
        case size
        case rawUrl = "raw_url"
        case type
        case truncated
        case language
    }
}

struct GitHubGistsContentOwner: Codable {
    let login: String
    let identity: Int
    let nodeIdentity: String
    let avatarUrl: URL
    let gravatarIdentity: String
    let url: URL
    let htmlUrl: URL
    let followersUrl: URL
    let followingUrl: URL
    let gistsUrl: URL
    let starredUrl: URL
    let subscriptionsUrl: URL
    let organizationsUrl: URL
    let reposUrl: URL
    let eventsUrl: URL
    let receivedEventsUrl: URL
    let type: String
    let siteAdmin: Bool

    private enum CodingKeys: String, CodingKey {
        case login
        case identity = "id"
        case nodeIdentity = "node_id"
        case avatarUrl = "avatar_url"
        case gravatarIdentity = "gravatar_id"
        case url
        case htmlUrl = "html_url"
        case followersUrl = "followers_url"
        case followingUrl = "following_url"
        case gistsUrl = "gists_url"
        case starredUrl = "starred_url"
        case subscriptionsUrl = "subscriptions_url"
        case organizationsUrl = "organizations_url"
        case reposUrl = "repos_url"
        case eventsUrl = "events_url"
        case receivedEventsUrl = "received_events_url"
        case type
        case siteAdmin = "site_admin"
    }
}

struct GitHubGistsContent: Codable {
    let url: URL
    let forkUrl: URL
    let commitUrl: URL
    let identity: String
    let nodeIdentity: String
    let description: String
    let isPublic: Bool
    let owner: GitHubGistsContentOwner
    let user: String?
    let files: Dictionary<String, GitHubGistsContentFile>?
    let truncated: Bool
    let comments: Int
    let commentsUrl: URL
    let htmlUrl: URL
    let gitPullUrl: URL
    let gitPushUrl: URL
    let createdDate: Date
    let updatedDate: Date

    private enum CodingKeys: String, CodingKey {
        case url
        case forkUrl = "forks_url"
        case commitUrl = "commits_url"
        case identity = "id"
        case nodeIdentity = "node_id"
        case description = "description"
        case isPublic = "public"
        case owner = "owner"
        case user
        case files
        case truncated
        case comments
        case commentsUrl = "comments_url"
        case htmlUrl = "html_url"
        case gitPullUrl = "git_pull_url"
        case gitPushUrl = "git_push_url"
        case createdDate = "created_at"
        case updatedDate = "updated_at"
    }
}

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"   // "2010-04-14T02:15:15Z"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)

do {
    let contents = try decoder.decode([GitHubGistsContent].self, from: json)
    print("contents = \(content)")
} catch {
    print(error)
}