ทดลองใช้ GraphQL ด้วย Apollo iOS

foursy p.
Nextzy
Published in
7 min readAug 18, 2019

จากบทความที่แล้วเราพูดถึงเรื่อง GraphQL เบื้องต้นกันไปแล้ว วันนี้เราจะมาทดลองใช้ในการทำโปรเจคจริงๆ กัน

หากใครที่ยังไม่มีความรู้พื้นฐานว่า GraphQL มันคืออะไร ดียังไง ใช้ยังไง แนะนำให้เข้าไปอ่าน บทความนี้ ก่อนเพื่อที่จะได้มีความเข้าใจเพิ่มมากขึ้น

ปัจจุบันนี้เริ่มมีการใช้งาน GraphQL อย่างแพร่หลายในบริษัทชั้นนำต่างๆ ส่งผลทำให้เกิด GraphQL Client ออกมาให้ user อย่างเราได้ใช้งานกันมากมายหลายเจ้า หนึ่งให้ผู้ให้บริการ GraphQL Client ที่เราเลือกมาใช้ในวันนี้คือ ‘Apollo iOS’ นั่นเอง

อะไรคือ Apollo iOS ?

Apollo iOS คือ GraphQL Client สำหรับการเขียนแอพ iOS ที่ใช้ภาษา Swift หรือพูดง่ายๆ ก็คือ เป็นเครื่องมือที่ช่วยให้เราสามารถติดต่อกับ API ผ่าน GraphQL ด้วยการส่ง query และ mutation ไปที่ server ให้นั่นเอง

นอกจากนั้น ข้อดีของการใช้ Apollo iOS คือข้อมูลที่ถูกส่งกลับมาจากฐานข้อมูลนั้น จะถูกทำให้อยู่ในรูปของ query-specific types ให้อัตโนมัติ

หมายความว่า จากปกติที่พอเราได้ผลลัพธ์ JSON มาจากการยิง request เราจะต้องมาวุ่นวายเอาไฟล์ตัวอักษรเหล่านั้นมาทำ parsing เพื่อให้มันกลายเป็น object ที่สามารถนำไปใช้ต่อได้ ไม่ต้องอีกต่อไปแล้วจ้า เพราะ Apollo (ขอเรียกแบบย่อๆ นะ) มันจัดการให้เราเรียบร้อย หรือแม้กระทั่งตัว model type ก็ไม่ต้องสร้างขึ้นมาใหม่ เพราะมันจัดการ auto generate มาให้เลยโดยอิงจาก API ที่เรากำลังใช้งาน

01 : มาเริ่มติดตั้งก่อนนะ

เริ่มแรกสิ่งที่เราจำเป็นจะต้องมีหากเราต้องการใช้งาน Apollo คือ
1) CocoaPods
2) Xcode (ก็แน่สิ จะเขียนแอพ iOS นะ!)
3) GraphQL Server หรือก็คือตัว API ที่เราจะไปดึงข้อมูลมาใช้นั่นแหละ ซึ่งในที่นี้เราก็จะมาลองสร้าง server ขึ้นมาเองแบบง่ายๆ ผ่าน Graphcool ด้วย แต่ถ้าใครมี server อยู่แล้วก็ใช้ของตัวเองไปนะ ไม่ต้องสร้างหรอก

นอกจากนี้ ถ้าใครอยากทดลองลงมือทำจริงก็สามารถ dowload sample project ที่นี่แล้วทำตามไปทีละขั้นตอนได้เลย

แล้วก็ขอข้ามขั้นตอนการติดตั้ง CocoaPods กับ Xcode ไปเลยละกัน เพราะง่ายมาก สามารถเข้าไปดูวิธีการ install ใน link ข้างบนได้ชิวๆ

มาเริ่มกันที่การสร้าง GraphQL Server

ก่อนที่จะ query หรือ mutate ข้อมูลได้ เราก็ต้องมีฐานข้อมูลก่อนนะสิ! ส่วนใครที่มีอยู่แล้วนั้น ข้ามไปขั้นตอนถัดไปเลยจ้า

  1. ติดตั้ง Graphcool CLI โดยใช้คำสั่ง npm install -g graphcool
  2. หลังจากติดตั้งเสร็จ ต่อมาให้เราไปที่ diretory ของตัว project (แนะนำให้เป็น directory ก่อนที่จะเข้าไปเจอ file .xcodeproj) แล้วสร้าง server ใหม่ขึ้นมาด้วยคำสั่ง graphcool init server
  3. จากนั้นเมื่อเราเข้าไปดูที่ directory ที่เรารันคำสั่ง จะเห็นว่ามีโฟลเดอร์ที่ชื่อว่า server’ เพิ่มขึ้นมา กดเข้าไปจะเจอไฟล์ชื่อว่า ‘types.graphql’ ซึ่งมันคือไฟล์ที่ใช้ในการตั้งค่า model ให้เราเปิดไฟล์นั้นขึ้นมา (ใช้ text editor อะไรก็ได้) แล้วลบข้อมูลเดิมออกให้หมด จากนั้นใส่สิ่งนี้ลงไปแทน
type Post @model {
# Required system field
id: ID! @isUnique # read-only (managed by Graphcool)
# Optional system fields (remove if not needed)
createdAt: DateTime! # read-only (managed by Graphcool)
updatedAt: DateTime! # read-only (managed by Graphcool)
description: String!
imageUrl: String!
}

4. หลังจากเราทำการตั้งค่าเสร็จก็จะสามารถ deploy ขึ้น server ที่สร้างก่อนหน้าได้ โดยให้เรา cd server ก่อนเพื่อเข้าไปยัง directory ของไฟล์ข้างต้น จากนั้นจึงใช้คำสั่ง graphcool deploy

ต่อมามันให้เราเลือก cluster ที่ต้องการจะ deploy ถ้าไม่อะไรก็เลือกอันแรกไปเลย (shared-eu-west-1) ซึ่งตรงนี้ขอสารภาพว่าไม่รู้จริงๆ ว่ามันจะมีผลอะไร55555

ต่อไปใส่ Target name กับ Project name ส่วนนี้ก็ตั้งได้ตามใจชอบเลย สมมติใช้ Instagram ทั้งคู่เลยละกัน เสร็จแล้ว enter โลด

จากนั้นจะใช้เวลาสักแปปนึง เมื่อ deploy สำเร็จก็จะมีข้อความแสดงขึ้นมาว่า ‘Success! Created the following service:’ ให้เราเลื่อนลงไปดูที่หัวข้อ Simple API แล้ว copy ลิ้งค์อันนั้นไว้ อย่าหายนะเพราะจำเป็นต้องใช้ต่อในส่วนต่อไป

ถ้าเรานำลิ้งค์อันนั้นไปเปิดใน browser จะเจอหน้าตาแบบนี้

เป็นอันเสร็จเรียบร้อย! ตอนนี้เราก็จะมี GraphQL Server จำลองของเป็นตัวเองแล้วจ้า

ได้ฤกษ์ติดตั้ง Apollo กันแล้ว

เมื่อเรามี server แล้ว ลำดับต่อมาก็คือการติดตั้งตัว Apollo iOS โดยให้เราไปเข้าใน directory ที่มีไฟล์นามสกุล .xcodeproj หรือก็คือโฟลเดอร์ที่เก็บไฟล์ Xcode project ของเรานั่นแหละ หลังจากนั้นทำตามขั้นตอนต่อไปนี้จ้า

  1. สำหรับใครที่ยังไม่ได้ติดตั้ง CocoaPods สามารถทำได้โดยการรันคำสั่ง
    sudo gem install cocoapods
  2. รันคำสั่ง pod init เพื่อสร้าง Podfile ขึ้นมา
  3. เปิด Podfile บน Xcode ด้วยคำสั่ง open -a Xcode Podfile
  4. ลบเครื่องหมาย ‘#’ หน้าบรรทัดที่เขียนว่า platform :iod, '9.0' ออกไป รวมถึง make sure ว่าไม่มีเครื่องหมายนี้หน้า use_framworks! เช่นเดียวกัน
  5. จากนั้นใต้บรรทัด use_framworks! ให้เราเพิ่มบรรทัด pod 'Apollo' ขึ้นมาแล้วกด Command (⌘)-S หรือ Ctrl+S เพื่อเซฟแล้วก็ปิดไปได้ละ
  6. สุดท้ายก็รันคำสั่ง pod install เพื่อติดตั้งได้เลย รอสักพักจะมีข้อความขึ้นมาว่า ‘Pod installation complete!’ แสดงว่าการติดตั้งเป็นอันเสร็จเรียบร้อย เย่!
หน้าตาของ Podfile ที่แก้ไขแล้วจะเป็นแบบนี้
หน้าตาของ Podfile ที่แก้ไขแล้วจะเป็นแบบนี้

หลังจากขั้นตอนนี้จะมีสิ่งที่เพิ่มขึ้นมา คือ โฟลเดอร์ Pods, ไฟล์ Podfile.lock, ไฟล์ .xcworkspace (สีขาวๆ) ซึ่งไฟล์นี้แหละที่เราจะใช้สำหรับสร้างโปรเจคนี้ต่อๆ ไป

หลังจากที่ติดตั้งตัว Apollo เข้ากับ project แล้ว ต่อมาให้เราทำการ download schema ของตัว API มาที่ directory เดิมโดยใช้คำสั่งว่า

apollo schema:download --endpoint=simple_API_endpoint schema.json

แทนที่ simple_API_endpoint ด้วยลิ้งค์ Simple API ที่เรา copy เก็บไว้ก่อนหน้านี้ ส่วน schema.json คือการบอกว่าเราต้องการ output file เป็น JSON file ที่มีชื่อว่า schema นั่นเอง

ระวัง!!!! ในบางครั้งถ้าเราใช้คำสั่งในการ download schema ผิด ถึงแม้จะ download ได้สำเร็จแต่จะเกิด error ตอน build project

เพราะฉะนั้นทางที่ดีควรใช้คำสั่งแบบด้านบนเป๊ะๆ จะดีกว่านะจ้ะ ไม่งั้นปวดหัวยาวๆ (เพราะผ่านมาแล้ววว ;_;) เมื่อเสร็จแล้วจะขึ้นแบบนี้เป็นอันว่าเรียบร้อย

ข้อความแสดงว่าการ download schema สำเร็จแล้วจ้า

ให้เราย้ายไฟล์ schema.json ที่อยู่ในโฟลเดอร์นั้นไปไว้ที่เดียวกับไฟล์ที่มีชื่อว่า ‘AppDelegate.swift’ ย้ำว่าต้องที่เดียวกันเท่านั้น และห้ามเอาทั้ง 2 ไฟล์นี้ไปยัดในโฟลเดอร์อื่นอีกนะ

นอกจากนั้นถ้าใครอยากให้มี syntax highlighting สามารถติดตั้งเพิ่มเติมโดยทำตาม instruction จาก link นี้ได้เลย (แต่ส่วนตัวไม่ได้ทำมันก็ขึ้นให้นะงงเหมือนกัน ใครไม่ขึ้นบอกด้วยยย)

ยังจ้ายังไม่จบง่ายๆ ไปต่อกันที่ขั้นตอนถัดไปเลย

เมื่อเราข้ามผ่านขึ้นตอนด้านบนแล้ว สิ่งสุดท้ายที่ต้องทำก็คือการตั้งค่า Build Phase ของตัวโปรเจค โดยทำตามสเต็ปนี้เลยจ้า

  1. เปิดไฟล์ .xcworkspace ที่บอกข้างบนขึ้นมา จากนั้นมองไปที่ sidebar ทางซ้ายแล้วเลือกที่ตัว application target
  2. ไปที่แท็บ Build Phase แล้วกดที่เครื่องหมาย (+) ที่มุมบนซ้าย เลือก option ที่เขียนว่า ‘New Run Script Phase’
  3. ดับเบิ้ลคลิกที่คำว่า ‘Run Script’ แล้วใส่ชื่อ ‘Generate Apollo GraphQL API’
  4. ในช่องที่เขียนว่า # Type a script or drag a script file from your workspace to insert its path. ให้เราวางสิ่งนี้ลงไปแทน
SCRIPT_PATH="${PODS_ROOT}/Apollo/scripts"
cd "${SRCROOT}/${TARGET_NAME}"
"${SCRIPT_PATH}"/check-and-run-apollo-cli.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile="schema.json" API.swift

5. เมื่อเสร็จ ให้เราลาก Build Phase อันนี้ไปไว้บนอันที่ชื่อว่า ‘Compile Sources’

หน้าจอแสดงการตั้งค่า New Run Script Phase

เป็นอันเสร็จสิ้นการ set up เบื้องต้นสำหรับการใช้งาน Apollo iOS เรียบร้อย เมื่อมาถึงขั้นตอนนี้ โปรเจคของเราก็พร้อมที่จะติดต่อสื่อสารกับ API ของเราแล้ว เรามาดูกันว่า ณ ตอนนี้เราได้ทำอะไรไปแล้วบ้าง

  • สร้าง API server จำลองขึ้นมาด้วย Graphcool
  • ติดตั้ง Apollo iOS เข้ากับตัวโปรเจคผ่าน CocoaPods
  • ดาวน์โหลด schema file ที่จำเป็นสำหรับการเชื่อมต่อกับ API
  • ตั้งค่า Build Phase สำหรับเรียกใช้เมื่อ build project

อาจจะฟังดูงงๆ ในตอนนี้ ไม่เป็นไรเพราะพอไปถึงขั้นตอนที่ต้องใช้เดี๋ยวจะอธิบายอีกทีว่ามันทำงานร่วมกันยังไงบ้างงง

02 : ได้เวลาลงมือกันแล้ว

โอเค หลังจากที่เราผ่านพ้นขั้นตอนอันน่าพิศวงด้านบนมา นั่นแสดงว่าเราได้พร้อมเข้าสู่โลกของ Apollo iOS อย่างสมบูรณ์แล้ว หลังจากนี้เราจะมาลองใช้งานจริงกันสักที แล้วจะเข้าใจเองว่าไอสิ่งที่เตรียมๆ มาก่อนหน้าเนี้ย มันเอามา put together กันยังไง

เมื่อเราทำการดาวน์โหลดตัว Sample project มาแล้ว หน้าตาของ App จะประมาณนี้

ตัวอย่างหน้าตาของ App หน้าแสดงฟีดภาพ (ซ้าย) หน้าเพิ่มภาพใหม่ (ขวา)

สิ่งที่เราจะลองทำในเบื้องต้น คือ
1. โหลดภาพจาก server เพื่อแสดงบนฟีดโดยใช้ query request
2. เพิ่มภาพใหม่เข้าไปที่ server โดยใช้ mutation request

การที่เราจะสามารถติดต่อสื่อสารกับ API ผ่าน Xcode นั้น เราต้องสร้าง Apollo Client เพื่อใช้ในการเชื่อมต่อ วิธีคือให้เราเข้าไปที่ไฟล์ AppDelegate.swift แล้วเพิ่มบรรทัดนี้เข้าไปบนสุดก่อน class declaration

import Apollo

let graphQLEndpoint = "__SIMPLE_API_ENDPOINT__"
let apollo = ApolloClient(url: URL(string: graphQLEndpoint)!)

และเช่นเคย _SIMPLE_API_ENDPOINT_ ก็ใส่ลิ้งค์ Simple API เป็นอันเรียบร้อยพร้อมลุยขั้นต่อไป

โหลดภาพมาแสดงบนหน้าฟีด

ก่อนที่เราจะสามารถโหลดภาพมาแสดงได้ เราจำเป็นจะต้องมีภาพที่ถูกเก็บอยู่บน server อยู่แล้ว เราจึงต้องเพิ่มภาพเข้าไปแบบ manual โดยไม่ผ่านหน้า App ก่อนจ้า

ให้เราเข้าไปที่หน้า Playground ของ API ที่เราสร้าง (หน้า Simple API บน browser) แล้วใส่คำสั่งนี้ลงไปในช่องฝั่งซ้ายโลด

mutation CreateFirstPost {
createPost(description: "My little girl ♡", imageUrl: "http://s24990.pcdn.co/wp-content/uploads/2017/02/cat2.jpg") {
id
description
imageUrl
updatedAt
}
}
mutation CreateSecondPost {
createPost(description: "Whoever said that money can't buy happiness simply didn't know where to go shopping.", imageUrl: "https://justflybusiness.co.uk/wp-content/uploads/2019/03/Shopping-Airports-for-Shopping.jpg") {
id
description
imageUrl
updatedAt
}
}

เสร็จแล้วกดปุ่ม Play ให้ครบทั้งสองคำสั่งที่ขึ้นมา ตอนนี้เราได้ทำการเพิ่ม 2 posts ลงไปแล้ว เพื่อเช็คว่าการเพิ่มสำเร็จมั้ย ให้ลอง query allPosts ออกมาดู ถ้าขึ้นมาครบก็แสดงว่าทำถูกต้องแล้วจ้าาา

ต่อมาเราจะดึง post ที่เราพึ่งเพิ่มเข้าไปนี่แหละไปแสดงบน App ของเรา โดยทำตามขั้นตอนด้านล่างเลยจ้า

ก่อนอื่นให้เราสร้าง folder ใหม่ที่ชื่อว่า GraphQL แล้วจึงสร้างไฟล์ใหม่ซึ่งเป็นไฟล์แบบ Empty โดยตั้งชื่อว่า PostTableViewController.graphql (ลบ .xib ออกไปด้วยนะจ้ะ) หลังจากนั้นใส่ query request แบบด้านล่างลงไปแทนที่ข้อมูลเดิม

fragment PostDetails on Post {
imageUrl
description
}
query GetAllPosts {
allPosts {
...PostDetails
}
}

อธิบายคร่าวๆ ก็คือ อันดับแรกเราจะต้องมีก้อนข้อมูลที่จะรองรับ result ที่เราได้ โดยใช้ keyword ว่า fragment ซึ่งเราจะต้องตั้งชื่อให้และบอกว่าให้มันรับข้อมูล type อะไรโดยใช้ keyword ว่า on แล้วจึงบอกด้านใน { } ว่าเราอยากจะได้ข้อมูลอะไร ส่วนใน query request ก็คล้ายๆ เดิมคือตั้งชื่อ ใส่คำสั่ง แต่ตรง return value ให้เราใส่ …FragmentName เช่น …PostDetails นั่นเอง

ps. ก่อน Build เพิ่ม pod 'Kingfisher' ใน Podfile แล้ว pod install ใหม่ก่อนน้า

จากนั้นเมื่อเรากด Command (⌘)-B หรือ Build ตัวโปรเจค ให้กลับไปดูที่ directory ของ project ของเรา ท๊าดาาาา!!!!!! จะมีไฟล์ที่ชื่อว่า API.swift โผล่ขึ้นมา ลากมันไปวางใน Xcode ใต้ GraphQL โดยไม่ต้องติ๊กถูกที่ Copy items if needed นะ

พอเข้าไปดูในไฟล์นี้ จะพบว่ามีโค้ดที่ถูกสร้างขึ้นมาตาม query request ที่เราเขียนด้านบน flow การทำงานก็คือ

เมื่อเรา Build โปรเจคครั้งแรกนั้น Build Phase ที่มีชื่อว่า ‘Generate Apollo GraphQL API’ จะไป invoke ให้เกิดการ generate representation code ตามไฟล์ .graphql โดยอิงข้อมูลจากไฟล์ schema.json ของเราเพื่อดูว่า characteristic ของตัว API ของเราเป็นยังไง มี type/request อะไรบ้าง และต้องสร้างโค้ดเพื่อติดต่อกันอย่างไร จากนั้นจึง generate โค้ดออกมาในไฟล์ API.swift นั่นเอง ว่างๆ ลองไปนั่งแกะโค้ดดูก็ได้นะ

Build ครั้งต่อไปมันจะไม่สร้างไฟล์ใหม่แล้วแต่จะเพิ่มหรือแก้ไขโค้ดในไฟล์นี้อัตโนมัติ

ขั้นต่อไปเมื่อเรามีช่องทางการติดต่อกับ API Server แล้ว ให้เราเข้าไปที่ไฟล์ PostTableViewController.swift จากนั้นให้ใส่โค้ดด้านล่างลงไปก่อนฟังก์ชั่นที่ชื่อว่า ViewDidLoad()

var posts: [PostDetails] = [] {
didSet {
tableView.reloadData()
}
}

โค้ดด้านบนคือการสร้างตัวแปรในโปรเจคเพื่อมารับข้อมูล โดยตั้ง variable type เป็น array ของ PostDetails (fragment) ส่วนใน ViewDidLoad() ก็ใส่แบบนี้ลงไป

let getAllPostsQuery = GetAllPostsQuery()
apollo.fetch(query: getAllPostsQuery) {
[weak self] result in
switch result {
case .failure(let error):
print(error.localizedDescription)
return
case .success(let graphQLResult):
guard let allPosts = graphQLResult.data?.allPosts else {
print("Cannot load all posts")
return
}
self?.posts = allPosts.map { ($0.fragments.postDetails) }
}
}

สิ่งที่เกิดขึ้นก็คือออ
1. สร้าง query ขึ้นมาจาก GetAllPostsQuery()
2. fetch คำสั่งนั้นแล้วดึง result กลับมา
3. เช็คว่า result สำเร็จหรือไม่ ถ้าไม่ก็ให้โชว์ error แล้วออกไปซะ ถ้าสำเร็จก็ทำต่อ
4. ถ้าสำเร็จก็แมพ result ที่ได้กับตัวแปรที่เราสร้างไว้โดยอิงจาก fragment

ps. ถ้าใครส่ง request เดิมไปหลายๆ รอบแล้วค่าไม่อัพเดท ให้ลองใส่เจ้านี่ cachePolicy: .fetchIgnoringCacheData ลงไปหลังตัวแปร query: ดูนะ เพราะมันจะมีสิ่งที่เรียกว่า cache ทำให้ค่ามันถูกเก็บไว้ไม่เปลี่ยน ขอไม่อธิบายเพราะจะยาว

เมื่อสำเร็จ ข้อมูลทั้งหมดก็จะถูกเก็บอยู่ในตัวแปรชื่อว่า posts ให้เราสามารถนำไปใช้ต่อไปได้ ดังนั้นเมื่อเราได้ทำการโหลดข้อมูลมาแล้ว ก็ไปกำหนดจำนวน row ที่จะแสดงผลตามจำนวน post ที่มี

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}

ต่อมาก็มาประมวลผลข้อมูลของแต่ละ row ว่าให้โชว์อะไรบ้างโดยดึงข้อมูลแต่ละ element ใน posts array

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! PostCell
cell.imageUrl = posts[indexPath.row].imageUrl
cell.descriptionLabel.text = posts[indexPath.row].description
return cell
}

เสร็จแล้วให้ Build and Run โปรเจค

หน้าแสดงภาพทั้งหมดที่เราดึงมากจาก Server

แท่มทะดะแด๊มมมมม! รูปภาพที่เราใส่ไปใน server ก่อนหน้าก็จะถูกเรียกมาแสดงในหน้านี้ละจ้า เย้ๆๆๆ

เพิ่มภาพใหม่เข้าไปหน่อยสิ้

หลังจากเราสามารถดึงภาพมาแสดงได้สำเร็จแล้ว ต่อไปเราจะมาลองเพิ่มภาพเข้าไปกันบ้าง สเต็ปก็ไม่ต่างจากตอนทำ query request เท่าไหร่

สร้าง Empty ไฟล์ขึ้นมาใหม่อีกอันในโฟลเดอร์ GraphQL ตั้งชื่อว่า AddPostViewController.graphql แล้วใส่ mutation request ด้านล่างเข้าไป

mutation CreatePost($imageUrl: String!, $description: String!) {
createPost(imageUrl: $imageUrl, description: $description) {
...PostDetails
}
}

เนื่องจากการที่จะสามารถเพิ่ม post เข้าไปได้นั้น เราจะต้องกำหนด imageUrl และ description ซึ่งจะรับมาจากหน้า New Post อีกที ดังนั้นการที่เราใส่ $imageUrl กับ $description ก็เพื่อบอกว่านี่คือชื่อตัวแปรที่จะต้องใส่เข้ามานะ ส่วน ! ก็คือบอกว่าจำเป็นจะต้องใส่นั่นเอง หลังจากนั้นจึงยัดค่าตัวแปรเข้าไปในคำสั่งตามที่ API กำหนด แล้วให้ return ออกมาเป็น PostDetails fragment เหมือนเดิม (มัน reusable)

ต่อกันเลย ให้เข้าไปที่ AddPostViewController.swift สิ่งที่เราจะทำคือพอกดปุ่ม Save จะสั่งให้ส่ง mutation request ไปที่ Server เพื่อเพิ่มข้อมูลใหม่เข้าไป ก่อนอื่นเพิ่มบรรทัดนี้ลงไปก่อน ViewDidLoad()

var createPost: ((PostDetails) -> ())?

และในฟังก์ชั่นชื่อ saveButtonPressed() ก็จะเป็นแบบนี้

let descriptionInput = descriptionTextField.text!
let imageUrlInput = imageUrlTextField.text!
let createPostMutation = CreatePostMutation(imageUrl: imageUrlInput, description: descriptionInput)
apollo.perform(mutation: createPostMutation) {
[weak self] result in
switch result {
case .failure(let error):
print(error.localizedDescription)
return
case .success(let graphQLResult):
self?.presentingViewController?.dismiss(animated: true) {
if let post = graphQLResult.data?.createPost?.fragments.postDetails {
self?.createPost?(post)
}
}
}
}

จากด้านบนจะเห็นว่าเรา
1. รับ input มาจาก text field ของ imageUrl และ description
2. ส่งข้อมูลที่รับมาไปยัง mutation request โดยใช้ชื่อตัวแปรตามที่ตั้งไว้ด้านบน
3. perform request แล้วเช็คว่าสำเร็จหรือไม่ ถ้าไม่ก็แสดง error แล้วออกเลย
4. ถ้าสำเร็จก็ dismiss หน้า New Post แล้วเอาผลลัพธ์ที่ return ออกมาใส่ในฟังก์ชั่น createPost() ที่สร้างเมื่อกี้

จากนั้นกลับไปที่ PostTableViewController.swift อีกรอบแล้วเพิ่มด้านล่างเข้าไปในฟังก์ชั่น prepare() ให้ออกมาหน้าตาเป็นงี้จ้า

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let addPostViewController = segue.destination as! AddPostViewController
addPostViewController.createPost = { post in
self.posts.append(post)
}
}

ก็คือเมื่อเราทำการเพิ่ม post เข้าไปยัง server แล้วก็ต้องเพิ่มเข้าไปใน array posts ด้วยไงจ้ะ พอเพิ่มเข้าไปมันก็จะไปรีโหลดข้อมูลอัตโนมัติแล้วแสดง post นั้นขึ้นมาทันทีเลย เสร็จแล้วกด Build and Run เหมือนเดิมแล้วลองเพิ่ม new post เข้าไป

ตัวอย่างการเพิ่ม New Post เข้าไปโดยใส่ Decription และ ImageUrl

โอ้วโหวววววมาแล้วจ้ารูปภาพที่เราพึ่งเพิ่มเข้าไป

ภาพใหม่ (ด้านล่าง) ที่แสดงขึ้นมาหลังจากทำการเพิ่ม New Post

นอกจากนั้นถ้าเราเข้าไปดูใน API Playground แล้วลอง query AllPosts ออกมาดู ก็จะมีข้อมูลของ post ที่เราพึ่งเพิ่มเข้าไปขึ้นมาแล้ว เย้!

สรุปส่งท้าย

ทั้งหมดก็คือตัวอย่างการใช้งาน Apollo iOS โดยอาศัย GraphQL ซึ่งมันทำให้การเชื่อมต่อกับ API เป็นไปได้อย่างสะดวกและง่ายดาย ไม่ค่อยมีอะไรซับซ้อนเท่าไหร่ ยังมีรายละเอียดเล็กๆ น้อยๆ อีกที่ยังสามารถเพิ่มเติมหรือปรับเปลี่ยนเพื่อเพิ่มประสิทธิภาพการทำงาน เช่น เรื่องเกี่ยวกับ cache, การทำ automatic update ด้วยการใช้ watch และอื่นๆ ยังไงก็ลองไปเล่นดูกันได้น้า

สำหรับบทความนี้ถ้ามีอะไรผิดพลาดตรงไหนก็บอกกันได้เลย เพราะเอาจริงๆ ก็ยังถือว่าเป็นมือใหม่ของ Apollo iOS เหมือนกัน มึนๆ งงๆ บ้างอะเนาะ ยังไงก็หวังว่าจะเป็นประโยชน์แก่คนอ่านไม่มากก็น้อยน้า วันนี้ขอตัวไปก่อน บ๊ายบายยย : )

References:

Original Sample Project (updated according to Apollo version) : https://github.com/graphcool-examples/ios-graphql https://www.apollographql.com/docs/ios/installation/
https://www.raywenderlich.com/595-getting-started-with-graphql-apollo-on-ios
https://medium.com/@dzungnguyen.hcm/graphql-in-ios-part-2-use-graphql-in-ios-1a2d81b54c11

--

--