-
[iOS] Apollo를 이용해 Graph QL 서버와 연동해보기 - 2Programing/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 }
이렇게 작성한 뒤 빌드를 해볼까요???
자 이렇게 서버에서 받아오는 데이터를 볼수가 있죠???🎉 🎉 🎉 🎉
이제 다음 포스팅으로 넘어가서 하나씩 이 코드가 어떻게 작동하는지 알아보도록 하죠!!!
수고하셨습니다.
'Programing > iOS' 카테고리의 다른 글
[iOS] Kakao/Daum Map 연동 (0) 2020.08.12 [iOS] 험난한 외주 앱스토어 등록기 (4) 2020.08.08 [iOS] Apollo를 이용해 Graph QL 서버와 연동해보기 - 1 (0) 2020.08.06 간단하게 알아보는 iOS 애니메이션 (0) 2020.07.02 Alomofire를 이용한 간단한 통신 방법 - (GET) (0) 2020.07.01