Creating a Simple iOS App Using URLSession GraphQL to Fetch Sitecore Items from a Sitecore 10.3 Docker Container
Introduction
After a lot of research and trying to explore Sitecore Headless feature I was able to create a simple iOS APP in order to get the items from Sitecore using GraphQL. In this blogpost I will demonstrate how you can use the Xcode 14.3.1 and the code needed to get the items from the Quiz app we were developing throughout this research. So I will start with the Xcode experience, and afterwards I will continue to see the modifications I do on Sitecore so you can see changes in real life. I needed to do this with two machines, a PC and a MacBookPro in order to demonstrate Sitecore's Headless capabilities.
Developing the iOS APP.
In the following APP, I used the following libraries: SwiftUI and URLSession. SwiftUI is used for the frontend part of the application and URLSession is an Apple library that controls REST requests. So in order for this to work I added a NetworkManager.swift class as follows:
//
// NetworkManager.swift
// SitecoreQuizApp
//
// Created by Ricardo Herrera Petit on 6/11/23.
//
import Foundation
class NetworkManager: NSObject, URLSessionDelegate {
let url = URL(string: "https://www.headlessapp.localhost/sitecore/api/graph/edge")!
var session: URLSession!
override init() {
super.init()
self.session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
}
func fetchQuizCategories(completion: @escaping (Result<[String], Error>) -> Void) {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("{F025A57B-C02F-4959-9B3D-2D72F579656A}", forHTTPHeaderField: "sc_apikey")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let body: [String: Any] = [
"query": """
query {
item(path: "/sitecore/content/HeadlessApp/Content/Quizzes", language: "en") {
id
children(includeTemplateIDs: ["2DD80D3EB1DA4DF0A915DC160A459079"]) {
results {
id,
name
}
}
}
}
"""
]
request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: [])
let task = session.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else {
completion(.failure(error!))
return
}
do {
let result = try JSONDecoder().decode(QueryResult.self, from: data)
let categories = result.data.item.children.results.map { $0.name }
completion(.success(categories))
} catch {
completion(.failure(error))
}
}
task.resume()
}
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
}
struct QueryResult: Codable {
let data: DataClass
}
struct DataClass: Codable {
let item: Item
}
struct Item: Codable {
let children: Children
}
struct Children: Codable {
let results: [ResultElement]
}
struct ResultElement: Codable {
let id, name: String
}
line 10 is where I assign the URL that is needed for the service. If you want to try it with your own service use the URL you have for your Sitecore instance. Also, keep in mind that this is a Proof of Concept and you should follow best practices in order to get the correct URL from iOS configurations. line 16 is the method fetchQuizCategories which was used later on the ContentView file in order to display the elements in the SwiftUI application.
line 18 assigns the method of the request.
line 19 adds the sc_apiKey , make sure to use yours.
then line 21 to line 35 is the query I am using on Postman on my previous blogs.
lines 37 to 57 is the way how you use URLSession in an iOS application which is outside of the scope of this blog post. Note that on line 44 I am only mapping the name, because is the only thing I care for showing the category, its name.
lines 61 to 72 are the response objects needed in order for this to work.
I also added a class QuizViewmodel.swift
// QuizViewModel.swift
// SitecoreQuizApp
//
// Created by Ricardo Herrera Petit on 6/11/23.
//
import Foundation
import SwiftUI
class QuizViewModel: ObservableObject {
@Published var quizCategories = [String]()
private var networkManager = NetworkManager()
func fetchQuizCategories() {
networkManager.fetchQuizCategories { [weak self] result in
DispatchQueue.main.async {
switch result {
case .success(let categories):
self?.quizCategories = categories
case .failure(let error):
print(“Failed to fetch quiz categories: \(error)“)
}
}
}
}
}
And this is the ContentView.Swift in order to see the APP on the simulator:// ContentView.swift
// SitecoreQuizApp
//
// Created by Ricardo Herrera Petit on 6/11/23.
//
import SwiftUI
struct ContentView: View {
@ObservedObject var viewModel = QuizViewModel()
var body: some View {
VStack {
Text(“Categories”)
.font(.largeTitle)
List(viewModel.quizCategories, id: \.self) { category in
Text(category)
}
}
.onAppear {
viewModel.fetchQuizCategories()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Proceed to run the simulator with the iOS App and you can see I get the categories shown from Sitecore and the app. Testing the App and Sitecore Item Integration
Now in order to see that the app is working and is headless we will see the items in Sitecore, and the items in the simulator. In the figure below are the items in Sitecore.
We see that Math and Science are the categories shown. Now if we run the app we will see the same thing on the figure below.
And now we run the iOS App again. Keep in mind that actually a refresh status should be implemented here for better user experience. But for the purposes of the PoC we will just make the app run again.
And there you go, Astronomy is now listed as we did in the Sitecore items.
If you want to follow along here is my github code for the iOS Application.
Conclusion
In conclusion, it is proven that Sitecore 10.3 is now a Headless CMS. Headless means that no Head is needed, since it relies on services to display its information. Using the services I was able to create an iOS application the way I wanted and get data from Sitecore. These can be done with many other applications such as Android, Flutter, React, Angular and any other platform that consumes REST API services. This is what is wonderful now, Sitecore CMS being headless can provide its information to any platform or device is requested.
Happy Coding !!! 😄😄😄
Comments
Post a Comment