JSON.swift 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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),
  12. let object = try? JSONCoding.decoder.decode(Self.self, from: data)
  13. else {
  14. return nil
  15. }
  16. self = object
  17. }
  18. var dictionaryRepresentation: [String: Any]? {
  19. guard let data = rawJSON.data(using: .utf8),
  20. let dict = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
  21. else {
  22. return nil
  23. }
  24. return dict
  25. }
  26. subscript(dynamicMember string: String) -> Any? {
  27. dictionaryRepresentation?[string]
  28. }
  29. }
  30. extension String: JSON {
  31. var rawJSON: String { self }
  32. init?(from: String) { self = from }
  33. }
  34. extension Double: JSON {}
  35. extension Int: JSON {}
  36. extension Bool: JSON {}
  37. extension Decimal: JSON {}
  38. extension Date: JSON {
  39. init?(from: String) {
  40. let dateFormatter = Formatter.iso8601withFractionalSeconds
  41. let string = from.replacingOccurrences(of: "\"", with: "")
  42. if let date = dateFormatter.date(from: string) {
  43. self = date
  44. } else {
  45. return nil
  46. }
  47. }
  48. }
  49. typealias RawJSON = String
  50. extension RawJSON {
  51. static let null = "null"
  52. }
  53. extension Array: JSON where Element: JSON {}
  54. extension Dictionary: JSON where Key: JSON, Value: JSON {}
  55. extension Dictionary where Key == String {
  56. var rawJSON: RawJSON? {
  57. guard let data = try? JSONSerialization.data(withJSONObject: self, options: .prettyPrinted) else { return nil }
  58. return RawJSON(data: data, encoding: .utf8)
  59. }
  60. }
  61. enum JSONCoding {
  62. static var encoder: JSONEncoder {
  63. let encoder = JSONEncoder()
  64. encoder.outputFormatting = [.prettyPrinted, .withoutEscapingSlashes]
  65. encoder.dateEncodingStrategy = .customISO8601
  66. return encoder
  67. }
  68. static var decoder: JSONDecoder {
  69. let decoder = JSONDecoder()
  70. decoder.dateDecodingStrategy = .customISO8601
  71. return decoder
  72. }
  73. }