JSON.swift 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import Foundation
  2. @dynamicMemberLookup protocol JSON: Codable {
  3. var rawJSON: String { get }
  4. init?(from: String)
  5. }
  6. extension JSON {
  7. var rawJSON: RawJSON {
  8. String(data: try! JSONCoding.encoder.encode(self), encoding: .utf8)!
  9. }
  10. init?(from: String) {
  11. guard let data = from.data(using: .utf8) else {
  12. return nil
  13. }
  14. do {
  15. let object = try JSONCoding.decoder.decode(Self.self, from: data)
  16. self = object
  17. } catch {
  18. warning(.service, "Cannot decode JSON", error: error)
  19. return nil
  20. }
  21. }
  22. var dictionaryRepresentation: [String: Any]? {
  23. guard let data = rawJSON.data(using: .utf8),
  24. let dict = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
  25. else {
  26. return nil
  27. }
  28. return dict
  29. }
  30. subscript(dynamicMember string: String) -> Any? {
  31. dictionaryRepresentation?[string]
  32. }
  33. }
  34. extension String: JSON {
  35. var rawJSON: String { self }
  36. init?(from: String) { self = from }
  37. }
  38. extension Double: JSON {}
  39. extension Int: JSON {}
  40. extension Bool: JSON {}
  41. extension Decimal: JSON {}
  42. extension Date: JSON {
  43. init?(from: String) {
  44. let dateFormatter = Formatter.iso8601withFractionalSeconds
  45. let string = from.replacingOccurrences(of: "\"", with: "")
  46. if let date = dateFormatter.date(from: string) {
  47. self = date
  48. } else {
  49. return nil
  50. }
  51. }
  52. }
  53. typealias RawJSON = String
  54. extension RawJSON {
  55. static let null = "null"
  56. static let empty = ""
  57. }
  58. extension Array: JSON where Element: JSON {}
  59. extension Dictionary: JSON where Key: JSON, Value: JSON {}
  60. extension Dictionary where Key == String {
  61. var rawJSON: RawJSON? {
  62. guard let data = try? JSONSerialization.data(withJSONObject: self, options: .prettyPrinted) else { return nil }
  63. return RawJSON(data: data, encoding: .utf8)
  64. }
  65. }
  66. enum JSONCoding {
  67. static var encoder: JSONEncoder {
  68. let encoder = JSONEncoder()
  69. encoder.outputFormatting = [.prettyPrinted, .withoutEscapingSlashes]
  70. encoder.dateEncodingStrategy = .customISO8601
  71. return encoder
  72. }
  73. static var decoder: JSONDecoder {
  74. let decoder = JSONDecoder()
  75. decoder.dateDecodingStrategy = .customISO8601
  76. return decoder
  77. }
  78. }