Introduction#
Github this day 3 shows
- Network request with async await
- Json decodable
- AsyncImage
- OpenSearch backend
Json Decodable#
Define the data models
struct MyNote: Codable {let DocumentTitle: Stringlet DocumentURI: String}struct MySource: Codable {let _id: Stringlet _source: MyNote}extension MySource: Identifiable {var id: String {return _id}}
request error handler
enum ApiError : Error {case badRequestcase badJson}
Network Request#
the ViewModel which perform the api call
class OpenSearchViewModel : ObservableObject {@Published var sources = [MySource]()init(){self.sources = []}func fetchNotes () async throws {// urlguard let url = URL(string: $OPENSEARCH_URI) else {return}let (data, response) = try await URLSession.shared.data(for: URLRequest(url: url))// handle response errorguard (response as? HTTPURLResponse)?.statusCode == 200 else {throw ApiError.badRequest}// handle parse errorguard let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {throw ApiError.badJson}guard let hits = json["hits"] as? [String: Any] else {throw ApiError.badJson}guard let ahits = hits["hits"] as? [Any] else {throw ApiError.badJson}do {let jsonData = try JSONSerialization.data(withJSONObject: ahits, options: [])let result = try JSONDecoder().decode([MySource].self, from: jsonData)Task {@MainActor inself.sources = result}} catch {throw ApiError.badJson}}}
Update UI#
search text as input textfield and present the list of opensearch results
struct OpenSearchView: View {@StateObject var viewModel = OpenSearchViewModel()@State private var searchText = ""var body: some View {NavigationView{List {ForEach(viewModel.notes) {note inNavigationLink(destination: Text(note._source.DocumentExcerpt)) {VStack {Text(note._source.DocumentTitle)Text(note._source.DocumentExcerpt)}}}}.searchable(text: $searchText, prompt: "Look for keywords").onSubmit(of: .search) {viewModel.getNotes(query: searchText)// searchText = ""}.navigationTitle("Searchable")}}}
and the main app
@mainstruct SwiftUI30DayApp: App {var body: some Scene {WindowGroup{OpenSearchView()}}}