-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use Xcode for server-side development #9
Comments
서론우리의 많은 응용 프로그램은 일반적으로 iPhone과 같은 단일 기기에 초점을 맞춥니다. 사용량이 늘어남에 따라 Mac, Watch, 기타 Apple 플랫폼 및 장치와 같은 추가 장치로 가져오고 싶어합니다. Xcode는 이러한 플랫폼을 위한 애플리케이션을 구성하고 구축하는데 도움이 됩니다. 플랫폼별 애플리케이션 코드에서 각 장치의 고유한 측면을 수용하면서 패키지를 사용하여 코드를 공유할 수 있습니다. 시스템이 성장하고 발전함에 따라서 응용 프로그램은 종종 서버 구성 요소로 클라이언트 응용 프로그램을 보완해야 합니다. 예를 들어, 백그라운드에서 수행할 수 있는 작업을 오프로드하거나 계산량이 많은 작업을 오프로드하거나 장치에서 사용할 수 없는 데이터에 액세스해야 하는 작업이 있습니다. 서버 구성 요소는 클라이언트 상대와 다른 도구와 방법론을 사용하여 구축해야 하므로 비용과 노력이 듭니다. 서버를 구축하기 위해 Swift를 사용하면 이러한 기술 격차를 해소하는 데 도움이 됩니다. Swift를 사용하여 서버 애플리케이션을 빌드하는 방법을 살펴봅시다. Swift 패키지로 서버 애플리케이션 구축서버 애플리케이션은 Swift 패키지로 모델링됩니다. 패키지는 애플리케이션 진입점을 매핑하는 실행가능한 대상을 정의합니다. // Package.swift
import PackageDescription
let package = Package(
name: "MyServer",
platforms: [.macOS("12.0")],
products: [
.executable(
name: "MyServer",
targets: ["MyServer"]),
],
dependencies: [
.package(url: "https://github.com/vapor/vapor.git", .upToNextMajor(from: "4.0.0")),
],
targets: [
.executableTarget(
name: "MyServer",
dependencies: [
.product(name: "Vapor", package: "vapor")
]),
.testTarget(
name: "MyServerTests",
dependencies: ["MyServer"]),
]
)
// Main : 진입점
import Vapor
@main
public struct MyServer {
public static func main() async throws {
let webapp = Application()
webapp.get("greet", use: Self.greet) // HTTP Endpoint
webapp.post("echo", use: Self.echo)
try webapp.run()
}
static func greet(request: Request) async throws -> String {
return "Hello from Swift Server"
}
static func echo(request: Request) async throws -> String {
if let body = request.body.string {
return body
}
return ""
}
}
iOS 앱에서 서버 호출하기
// MyServerClient.swift
import Foundation
struct MyServerClient {
let baseURL = URL(string: "http://127.0.0.1:8080")!
func greet() async throws -> String {
let url = baseURL.appendingPathComponent("greet")
let (data, _) = try await URLSession.shared.data(for: URLRequest(url: url))
guard let responseBody = String(data: data, encoding: .utf8) else {
throw Errors.invaildResponseEncoding
}
return responseBody
}
enum Errors: Error {
case invaildResponseEncoding
}
} // ContentView.swift
import SwiftUI
struct ContentView: View {
@State var serverGreeting = ""
var body: some View {
Text(serverGreeting)
.padding()
.task {
do {
let myServerClient = MyServerClient()
self.serverGreeting = try await myServerClient.greet()
} catch {
self.serverGreeting = String(describing: error)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
} 클라우드에 배포하기
Food Truck App
iOS 또는 macOS 애플리케이션을 빌드하기 위해 이미 Swift를 사용하고 있다면 시스템의 서버 측 개발에도 사용할 수 있습니다. Xcode는 하나의 작업 공간에서 클라이언트와 서버 모두 시스템의 다양한 구성 요소를 개발하고 디버그하는데 도움이 됩니다. Swift 기반 서버 애플리케이션을 배포하기 위한 클라우드 공급자를 선택할 수도 있습니다. 우리가 푸드 트럭을 운용하기 위해 앱을 사용한다고 가정해본채로 이해해보도록 할게요. 예시 앱을 들여다보면 데이터가 하드코딩된 채로 관리되는 것을 볼 수 있습니다. 그렇다면 유저는 실제로 다른 데이터를 볼 수도 있겠네요. 소규모 푸드 트럭 운용에는 괜찮을 수 있겠지만 여러 개의 푸드 트럭에서 하나의 서비스를 이용해서 운용을 한다고 생각을 해보면 비효율적인 방식이 될 수 있을 것 같습니다. 우리는 지금 메뉴가 중앙 집중화되고 모든 고객 서비스를 관리하는 도넛 제국을 만들고 싶은 것입니다. 중앙 집중 시스템을 어떻게 만들 수 있을지 생각해보죠. 메모리 내 저장소가 있는 앱에서 시작해볼까요? 메뉴를 중앙 집중화하기 위해서 iOS 앱에서 스토리지를 추출하여 서버로 이동할 수 있습니다. 이렇게 하면 앱의 모든 사용자가 동일한 저장소를 공유할 수 있기 때문에 동일한 도넛 메뉴를 사용할 수 있습니다. 첫번째 예제와 마찬가지로 HTTP 기반 API에 노출되어 있습니다. iOS 앱은 이러한 API 작업을 위해 추상화를 사용한 다음 Presentation Layer(이 예에서는 SwiftUI)에 연결합니다. 코드@main
struct FoodTruckServerBootstrap {
public static func main() async throws {
let foodTruckServer = FoodTruckServer()
let webapp = Application()
webapp.get("donuts", use: foodTruckServer.listDonuts) // Set Endpoints
try webapp.run()
}
}
struct FoodTruckServer {
func listDonuts(request: Request) -> Response.Donuts{
return Reponse.Donuts(donuts: [])
}
enum Response {
struct Donuts: Content {
var donuts: [Model.Donut]
}
}
}
enum Model {
struct Donut: Encodable {
public var id: UUID
public var name: String
public var date: String
public var dough: Dough
public var glaze: Glaze?
public var topping: Topping?
}
struct Dough: Encodable {
}
struct Glaze: Encodable {
}
struct Topping: Encodable {
}
}
struct FoodTruckServer {
private let storage = Storage()
func listDonuts(request: Request) -> Response.Donuts {
let donuts = self.storage.listDonuts()
return Response.Donuts(donuts: [])
}
enum Response {
struct Donuts: Content {
var donuts: [Model.Donut]
}
}
}
struct Storage {
let donuts = [Model.Donut]()
func listDonuts() -> [Model.Donut] {
return self.donuts
}
}
스토리지(Storage)
정적 파일 저장 전략
서버 추상화(abstraction)에 bootstrap메서드를 추가하고 거기에서 스토리지를 로드합니다. 그리고 bootstrap을 실행 가능한 진입점에 연결합니다. 스토리지는 이제 액터이므로 비동기 컨텍스트에서 접근하도록 합니다. 서버 API를 캡슐화하는 데 도움이 됩니다. 기존 방식과 마찬가지로 URLSession을 이용해서 HTTP 요청을 만들고 JSONDecoder를 사용하여 서버 응답을 디코딩하고 JSON에서 iOS 애플리케이션 모델로 변환합니다. 상위 수준에서 사용하기iOS와 서버 애플리케이션에서 모델을 공유함으로써 반복을 피하고 직렬화를 더 안전하게 만들 수 있습니다. 다음은 데이터 모델 코드를 Shared 프레임워크로 옮겨서 사용하고 있습니다. |
The text was updated successfully, but these errors were encountered: