Perfect 라우팅
지난 번에는 Perfect 서버 애플리케이션을 처음 구동해 보았습니다.
이번에는 라우팅 하는 방법에 대해서 알아보려고 합니다 🙂
참고
2017년 5월 현재 Swift 3 / Perfect 최신버전 2.0.x 환경에서 진행함을 알려드립니다.
Routes
HTTP 요청에 의해 여러 메서드, URI에 따른 동작을 처리하려면 Routes
라는 구조체를 사용합니다.
지난 번 main.Swift파일에 서버 포트를 지정해 주었던 server.serverPort = 8080
코드 아래에 routes
변수에 Routes
인스턴스를 하나 할당해줍니다.
라우터를 생성할 때, 원하는 HTTP Method와 URI를 지정할 수 있으며, 요청이 온 경우 handler
클로저를 통해 요청을 처리합니다.
var routes = Routes()
HTTP Method, URI 지정
Routes
인스턴스를 생성할 때, 원하는 HTTP Method와 URI를 지정할 수 있으며, 요청이 온 경우 handler
클로저를 통해 요청을 처리합니다. 이후, addRoutes()
메서드를 통해 서버에 라우트 정보를 추가해줍니다.
routes.add(method: .get, uri: "/blog", handler: { request, response in
response.setBody(string: "Blog handler was called")
response.completed()
})
server.addRoutes(routes)
이렇게 지정하고 실행하면 8080
포트의 blog
경로를 지정하여 호출하면 "Handler was called" 문자열이 돌아오게 될 것입니다.
handler
클로저의 내부에서 request
인스턴스에서 param(name:)
등 많은 메서드를 통해 HTTP 요청 정보를 읽어낼 수 있습니다.
routes.add(method: .get, uri: "/blog", handler: { request, response in
let pageToResponse: Int
if let page = request.param(name: "page"), let pageNumber = Int(page) {
pageToResponse = pageNumber
} else {
pageToResponse = 0
}
response.setBody(string: "Handler was called page number: \(pageToResponse)")
response.completed()
})
Web Root 디렉터리 설정
연습을 해봤으니 실질적으로 HTML 응답과 JSON 응답을 해보려합니다. 먼저 웹의 데이터를 모아 둘 WebDocuments 폴더를 사용자 디렉터리의 하위폴더로 생성해줍니다.
> mkdir ~/WebDocuments
WebDocuments 폴더를 생성하면 블로그 메인페이지로 사용할 index.html 파일을 넣어줍니다. (파일을 이동하거나 복사하는 방법에 대해서는 따로 설명하지 않겠습니다... 'ㅁ')
이제 WebDocuments 폴더를 웹서버의 Root 폴더로 지정합니다.
사용자 디렉터리의 주소를 가져오기 위해 Foundation
프레임워크를 이용했습니다. main.swift 파일 상단에 import Foundation
을 통해 Foundation
프레임워크를 불러와주세요.
그리고 아래 코드를 server.addRoutes(routes)
라인 아래에 작성해주세요.
if let homeURL = URL(string: NSHomeDirectory()) {
var rootPath = homeURL.appendingPathComponent("WebDocuments", isDirectory: true).absoluteString
try Dir(rootPath).create()
server.documentRoot = rootPath
}
이렇게 설정하고 하위 경로 없이 접속하면 WebDocuments 폴더의 index.html 파일을 자동으로 메인 페이지로 볼 수 있습니다.
JSON 응답
이번에는 단순히 HTML 웹페이지가 아닌 JSON 응답을 줘보려고 합니다. 먼저 응답을 제어하기 위한 handler
클로저를 따로 함수로 구현하려 합니다. 가독성 면에서도 그게 좋을 것 같아요.
서버 인스턴스 생성코드 let server = HTTPServer()
전에 handler 함수를 구현해봅니다.
func jsonHandler(request: HTTPRequest, response: HTTPResponse) {
var jsonDictionary: [String: Any] = [:]
jsonDictionary["name"] = "yagom"
jsonDictionary["languages"] = ["Swift", "Objective-C"]
jsonDictionary["age"] = 10
jsonDictionary["alive"] = true
do {
response.setHeader(.contentType, value: "application/json; charset=utf-8")
try response.setBody(json: jsonDictionary)
response.completed()
} catch {
response.completed(status: .internalServerError)
}
}
그리고 경로를 지정해주기 위해서 server.addRoutes(routes)
코드 위에 아래 코드를 작성합니다.
routes.add(method: .get, uri: "/json", handler: jsonHandler(request:response:))
다시 실행해서 /json 경로로 GET 요청을 하면 아래와같이 JSON 문자열을 응답한 것을 확인할 수 있습니다.
정리
지금까지 작성한 main.swift 파일 코드
import PerfectLib
import PerfectHTTP
import PerfectHTTPServer
import Foundation
func jsonHandler(request: HTTPRequest, response: HTTPResponse) {
var jsonDictionary: [String: Any] = [:]
jsonDictionary["name"] = "yagom"
jsonDictionary["languages"] = ["Swift", "Objective-C"]
jsonDictionary["age"] = 10
jsonDictionary["alive"] = true
do {
response.setHeader(.contentType, value: "application/json; charset=utf-8")
try response.setBody(json: jsonDictionary)
response.completed()
} catch {
response.completed(status: .internalServerError)
}
}
let server = HTTPServer()
server.serverPort = 8080
var routes = Routes()
routes.add(method: .get, uri: "/blog", handler: { request, response in
let pageToResponse: Int
if let page = request.param(name: "page"), let pageNumber = Int(page) {
pageToResponse = pageNumber
} else {
pageToResponse = 0
}
response.setBody(string: "Handler was called page number: \(pageToResponse)")
response.completed()
})
routes.add(method: .get, uri: "/json", handler: jsonHandler(request:response:))
server.addRoutes(routes)
if let homeURL = URL(string: NSHomeDirectory()) {
var rootPath = homeURL.appendingPathComponent("WebDocuments", isDirectory: true).absoluteString
try Dir(rootPath).create()
server.documentRoot = rootPath
}
do {
try server.start()
} catch PerfectError.networkError(let error, let message) {
Log.error(message: "Error: \(error), \(message)")
}
물론 이 외에도 정말 많은 응용 방법과 라우트 하는 방법, 더 다양한 기능들이 있지만 모두 설명할 수 없으므로 정말 간단하게 감을 잡을 수 있는 정도만 해봤습니다. 차후에 간단한 프로젝트를 통해서 필요한 부분은 조금씩 더 설명하려고 합니다.
이정도 만들어 봤으면 대강 핑퐁은 해봤으니, 작은 미니 프로젝트 한 번 시작해 봐도 되지 않을까요?
다음 번에는 미니 프로젝트를 시작해볼 예정입니다~
다음에 또 만나요! 😀
참고문서
by yagom
facebook : https://www.facebook.com/yagompage
facebook group : https://www.facebook.com/groups/yagom
p.s 제 포스팅을 RSS 피드로 받아보실 수 있습니다.
RSS Feed 받기