ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [iOS] Apollo를 이용해 Graph QL 서버와 연동해보기 - 2
    Programing/iOS 2020. 8. 7. 17:34

    안녕하세요~!🙋🙋🙋 5anniversary 입니다~!~!~!~!

     

    이번 포스팅에서는 저번 apollo 활용 첫번째 포스팅에 이어서 서버 데이터를 받아오는 시간을 가져볼거에요~!~!

     

    우선 GraphQL이 어떻게 사용되는지 간단하게 알아볼까요???

     

    GraphQL은 거의 공통적으로 query를 클라이언트 레벨에서 request 해주면 server에서 해당 query를 승인 해준뒤 알맞는 데이터를 보내주는 구조에요!! 이런 구조를 글로만 설명하면 이해가 좀... 힘들겠죠??? 보러가시죠~! 

     

    사이트에 들어가시죠!! 

     

    사이트에 들어가면 이런 화면이 나올거에요!!

     

     

    오른쪽의 Docs를 누르면 이 서버에서 제공하는 GraphQL의 query리스트가 있구요!!

    schema를 누르면 이 서버에서 제공하는 GraphQL의 shema를 보여줍니다.

     

    여기서 데이터가 어떤 방식으로 전달되는지 볼게요!!

     

    왼쪽 창에 

    query {
      launches{
        cursor
        hasMore
      }
    }

    와 같은 쿼리를 넣어주세요!!

     

    그럼 이렇게 데이터가 나오게 돼요!!

     

    여기서 원하는 데이터들을 알맞게 받아올수있는데요!!

     

    docs를 보고 원하는 데이터들을 쿼리 리스트에 넣어주세요!!

     

    query {
      launches{
      	cursor
        hasMore
        launches{
          id
        }
      }
    }

     

    이런 쿼리를 넣어주면 이렇게 나온답니다~!

     

    이제 GraphQL이 어떤 방식으로 구현되는지 알아봤으니 구현을 해볼까여~??

     

    empty 파일으로 LaunchList.graphql 라는 이름의 파일을 만들어 볼게요~! 여기서도 조건이 있는데요

     

    1. Target이 설정되어있으면 안되구요

    2. schema.json 파일과 같은 레벨에 위치해 있어야합니다.

     

    그리고 이제 알맞는 쿼리를 넣어줄까요??

     

    query LaunchList($cursor:String) {
      launches(after:$cursor) {
        hasMore
        cursor
        launches {
          id
          site
          mission {
            name
            missionPatch(size: SMALL)
          }
        }
      }
    }
    

    여기서는 cursor를 페이징처리를 위해 받아서 넘겨주는 방식으로 처리합니다.

     

    그리고~!

     

    네트워크 관련 코드를 작성해야겠죠????

     

    import Apollo
    
    class Network {
      static let shared = Network()
        
        private(set) lazy var apollo: ApolloClient = {
            let httpNetworkTransport =
            HTTPNetworkTransport(url: URL(string: "https://apollo-fullstack-tutorial.herokuapp.com/")!)
            httpNetworkTransport.delegate = self
            return ApolloClient(networkTransport: httpNetworkTransport)
        }()
    }
    
    extension Network: HTTPNetworkTransportPreflightDelegate {
        func networkTransport(_ networkTransport: HTTPNetworkTransport,
                              shouldSend request: URLRequest) -> Bool {
            return true
        }
        
        func networkTransport(_ networkTransport: HTTPNetworkTransport,
                              willSend request: inout URLRequest) {
        }
    }
    

    를 만들고 작성해주세요~!

     

    그 다음 service코드를 작성할건데요 

     

    import Apollo
    
    public final class LaunchListQuery: GraphQLQuery {
      /// The raw GraphQL definition of this operation.
      public let operationDefinition: String =
        """
        query LaunchList($cursor: String) {
          launches(after: $cursor) {
            __typename
            hasMore
            cursor
            launches {
              __typename
              id
              site
              mission {
                __typename
                name
                missionPatch(size: SMALL)
              }
            }
          }
        }
        """
    
      public let operationName: String = "LaunchList"
    
      public var cursor: String?
    
      public init(cursor: String? = nil) {
        self.cursor = cursor
      }
    
      public var variables: GraphQLMap? {
        return ["cursor": cursor]
      }
    
      public struct Data: GraphQLSelectionSet {
        public static let possibleTypes: [String] = ["Query"]
    
        public static let selections: [GraphQLSelection] = [
          GraphQLField("launches", arguments: ["after": GraphQLVariable("cursor")], type: .nonNull(.object(Launch.selections))),
        ]
    
        public private(set) var resultMap: ResultMap
    
        public init(unsafeResultMap: ResultMap) {
          self.resultMap = unsafeResultMap
        }
    
        public init(launches: Launch) {
          self.init(unsafeResultMap: ["__typename": "Query", "launches": launches.resultMap])
        }
    
        public var launches: Launch {
          get {
            return Launch(unsafeResultMap: resultMap["launches"]! as! ResultMap)
          }
          set {
            resultMap.updateValue(newValue.resultMap, forKey: "launches")
          }
        }
    
        public struct Launch: GraphQLSelectionSet {
          public static let possibleTypes: [String] = ["LaunchConnection"]
    
          public static let selections: [GraphQLSelection] = [
            GraphQLField("__typename", type: .nonNull(.scalar(String.self))),
            GraphQLField("hasMore", type: .nonNull(.scalar(Bool.self))),
            GraphQLField("cursor", type: .nonNull(.scalar(String.self))),
            GraphQLField("launches", type: .nonNull(.list(.object(Launch.selections)))),
          ]
    
          public private(set) var resultMap: ResultMap
    
          public init(unsafeResultMap: ResultMap) {
            self.resultMap = unsafeResultMap
          }
    
          public init(hasMore: Bool, cursor: String, launches: [Launch?]) {
            self.init(unsafeResultMap: ["__typename": "LaunchConnection", "hasMore": hasMore, "cursor": cursor, "launches": launches.map { (value: Launch?) -> ResultMap? in value.flatMap { (value: Launch) -> ResultMap in value.resultMap } }])
          }
    
          public var __typename: String {
            get {
              return resultMap["__typename"]! as! String
            }
            set {
              resultMap.updateValue(newValue, forKey: "__typename")
            }
          }
    
          public var hasMore: Bool {
            get {
              return resultMap["hasMore"]! as! Bool
            }
            set {
              resultMap.updateValue(newValue, forKey: "hasMore")
            }
          }
    
          public var cursor: String {
            get {
              return resultMap["cursor"]! as! String
            }
            set {
              resultMap.updateValue(newValue, forKey: "cursor")
            }
          }
    
          public var launches: [Launch?] {
            get {
              return (resultMap["launches"] as! [ResultMap?]).map { (value: ResultMap?) -> Launch? in value.flatMap { (value: ResultMap) -> Launch in Launch(unsafeResultMap: value) } }
            }
            set {
              resultMap.updateValue(newValue.map { (value: Launch?) -> ResultMap? in value.flatMap { (value: Launch) -> ResultMap in value.resultMap } }, forKey: "launches")
            }
          }
    
          public struct Launch: GraphQLSelectionSet {
            public static let possibleTypes: [String] = ["Launch"]
    
            public static let selections: [GraphQLSelection] = [
              GraphQLField("__typename", type: .nonNull(.scalar(String.self))),
              GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))),
              GraphQLField("site", type: .scalar(String.self)),
              GraphQLField("mission", type: .object(Mission.selections)),
            ]
    
            public private(set) var resultMap: ResultMap
    
            public init(unsafeResultMap: ResultMap) {
              self.resultMap = unsafeResultMap
            }
    
            public init(id: GraphQLID, site: String? = nil, mission: Mission? = nil) {
              self.init(unsafeResultMap: ["__typename": "Launch", "id": id, "site": site, "mission": mission.flatMap { (value: Mission) -> ResultMap in value.resultMap }])
            }
    
            public var __typename: String {
              get {
                return resultMap["__typename"]! as! String
              }
              set {
                resultMap.updateValue(newValue, forKey: "__typename")
              }
            }
    
            public var id: GraphQLID {
              get {
                return resultMap["id"]! as! GraphQLID
              }
              set {
                resultMap.updateValue(newValue, forKey: "id")
              }
            }
    
            public var site: String? {
              get {
                return resultMap["site"] as? String
              }
              set {
                resultMap.updateValue(newValue, forKey: "site")
              }
            }
    
            public var mission: Mission? {
              get {
                return (resultMap["mission"] as? ResultMap).flatMap { Mission(unsafeResultMap: $0) }
              }
              set {
                resultMap.updateValue(newValue?.resultMap, forKey: "mission")
              }
            }
    
            public struct Mission: GraphQLSelectionSet {
              public static let possibleTypes: [String] = ["Mission"]
    
              public static let selections: [GraphQLSelection] = [
                GraphQLField("__typename", type: .nonNull(.scalar(String.self))),
                GraphQLField("name", type: .scalar(String.self)),
                GraphQLField("missionPatch", arguments: ["size": "SMALL"], type: .scalar(String.self)),
              ]
    
              public private(set) var resultMap: ResultMap
    
              public init(unsafeResultMap: ResultMap) {
                self.resultMap = unsafeResultMap
              }
    
              public init(name: String? = nil, missionPatch: String? = nil) {
                self.init(unsafeResultMap: ["__typename": "Mission", "name": name, "missionPatch": missionPatch])
              }
    
              public var __typename: String {
                get {
                  return resultMap["__typename"]! as! String
                }
                set {
                  resultMap.updateValue(newValue, forKey: "__typename")
                }
              }
    
              public var name: String? {
                get {
                  return resultMap["name"] as? String
                }
                set {
                  resultMap.updateValue(newValue, forKey: "name")
                }
              }
    
              public var missionPatch: String? {
                get {
                  return resultMap["missionPatch"] as? String
                }
                set {
                  resultMap.updateValue(newValue, forKey: "missionPatch")
                }
              }
            }
          }
        }
      }
    }
    

    예시로 나와있는 코드는 이렇게 되는데요 우선 이번 시간에는 실행 해보고~~

     

    다음 포스팅에서 자세히 알아보도록 할게요~~~

     

    그리고 이 서버 코드를 실행시키는 코드도 있어야겠죠??

     

    예시에서는 어플을 실행시키자마자 서버 연동이 되는지 확인 하기 위해서 AppDelegate에 넣어줬는데요

     

        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch.
            Network.shared.apollo.fetch(query: LaunchListQuery()) { result in
              switch result {
              case .success(let graphQLResult):
                print(graphQLResult)
              case .failure(let error):
                print("Failure! Error: \(error)")
              }
            }
    
            return true
        }
    

     

    이렇게 작성한 뒤 빌드를 해볼까요???

     

    자 이렇게 서버에서 받아오는 데이터를 볼수가 있죠???🎉 🎉 🎉 🎉 

     

    이제 다음 포스팅으로 넘어가서 하나씩 이 코드가 어떻게 작동하는지 알아보도록 하죠!!!

     

    수고하셨습니다.

     

     

    댓글

Designed by Tistory.