Swift: Networking: Simple Request
Performing network communication in Swift is enabled using URLSession. A very simple request can be implemented with the asynchronous method `data(from: URL)` using just a couple of code lines.
For easy testing the Python package FastAPI provides a very simple and quick means. That way handling network requests can be tested in the simulator while the server can be started on the developer computer.
Preparing a FastAPI Server
There are two script files needed. One to prepare the Python environment and another which contains the FastAPI app. Disclaimer: This is not production ready code, so don't use it as such.
Setup script `minisrv_venv.sh`:
#!/bin/sh
if [ -d ./venv ]; then
source ./venv/bin/activate
else
python3 -m venv ./venv
source ./venv/bin/activate
python3 -m pip install fastapi[standard]
fi
fastapi run minisrv.py
deactivate
FastAPI Python script `minisrv.py`:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"result": "hi"}
Running the FastAPI server
To run the FastAPI server open a Terminal in the directory with these two script files.
Run the following command:
% sh ./minisrv_venv.sh
Press Ctrl-C to stop the FastAPI server when you don't need it any more or you want to restart it.
Performing the Network Request in Swift
To fetch the data, simply call `data(from: URL)` like shown in this function:
private func sendRequest() {
Task {
do {
guard let url = URL(string: "http://localhost:8000/") else { return }
let (data, resp) = try await URLSession.shared.data(from: url)
if let httpResp = resp as? HTTPURLResponse {
self.responseStatus = "\(httpResp.statusCode)"
if httpResp.statusCode != 200 {
self.responseInfo = "Error: Expected 200"
return
}
}
guard let string = String(data: data, encoding: .utf8) else { return }
self.response = string
self.responseInfo = "OK"
self.errorInfo = "-"
} catch {
self.response = "-"
self.responseStatus = "-"
self.responseInfo = "-"
self.errorInfo = "\(error.localizedDescription)"
}
}
}
The full source code with the complete SwiftUI view is shown below:
import SwiftUI
struct SimpleRequestView: View {
@State private var response: String = "-"
@State private var responseStatus: String = "-"
@State private var responseInfo: String = "-"
@State private var errorInfo: String = "-"
var body: some View {
VStack {
Text("Simple Request")
.font(.largeTitle)
Form {
Button(action: {
sendRequest()
}, label: {
Label("Send", systemImage: "paperplane")
})
LabeledContent("Response", value: response)
LabeledContent("Response Status", value: responseStatus)
LabeledContent("Response Info", value: responseInfo)
LabeledContent("Error Info", value: errorInfo)
}
}
}
private func sendRequest() {
Task {
do {
guard let url = URL(string: "http://localhost:8000/") else { return }
let (data, resp) = try await URLSession.shared.data(from: url)
if let httpResp = resp as? HTTPURLResponse {
self.responseStatus = "\(httpResp.statusCode)"
if httpResp.statusCode != 200 {
self.responseInfo = "Error: Expected 200"
return
}
}
guard let string = String(data: data, encoding: .utf8) else { return }
self.response = string
self.responseInfo = "OK"
self.errorInfo = "-"
} catch {
self.response = "-"
self.responseStatus = "-"
self.responseInfo = "-"
self.errorInfo = "\(error.localizedDescription)"
}
}
}
}
#Preview {
SimpleRequestView()
}