don't stop believing

[Swift] Perfect 서버 기본 알아보기 본문

Swift/Perfect

[Swift] Perfect 서버 기본 알아보기

Tongchun 2017. 9. 11. 12:09

swift Server-Side Framework이 여러가지가 있는데 이번에는 Perfect를 배워봅시다.

Perfect는 swift 3.0.1 이상 버전이어야 합니다.

$ swift --version
Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42)
Target: x86_64-apple-macosx10.9

나는 swift 3.1 버전이군요.

먼저 Terminal을 열고 생성하려는 프로젝트 명으로 폴더를 만듭니다. 그리고 해당 폴더 안 에서 package를 초기화 합니다.

$ mkdir nGleServer006
$ cd nGleServer006
$ swift package init --type executable

그럼 Package.swift 파일과 몇개의 폴더가 생성됩니다.

그리고 바로 xCode 프로젝트로 변환해 줍니다.

$ swift package generate-xcodeproj

폴더안에 nGleServer006.xcodeproj 라고 xCode 프로젝트 파일이 생성되면 xCode로 프로젝트를 열어 줍니다.

터미널에서 바로 파일을 실행시킬 수도 있습니다.

$ open ./nGleServer006.xcodeproj/

xCode로 실행해서 바로 build 버튼을 클릭해 봅니다.

하단 Debug 창에 Hello, world!를 확인할 수 있습니다.

Package.swift 파일에 dependencies 를 아래처럼 추가합니다.

let package = Package(
    name: "nGleServer006",
    dependencies: [
        .Package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", majorVersion: 2)
    ]
)

저장 후 다시 터미널에서 package update를 해줍니다. 그럼 Perfect-HTTPServer에 대한 프레임워크를 다운로드 합니다.

$ swift package update

Perfect-HTTPServer Package를 적용하면 아래 Package들도 함께 추가됩니다.

Fetching https://github.com/PerfectlySoft/Perfect-HTTPServer.git

Fetching https://github.com/PerfectlySoft/Perfect-Net.git

Fetching https://github.com/PerfectlySoft/Perfect-HTTP.git

Fetching https://github.com/PerfectlySoft/Perfect-Crypto.git

Fetching https://github.com/PerfectlySoft/Perfect-Thread.git

Fetching https://github.com/PerfectlySoft/PerfectLib.git

Fetching https://github.com/PerfectlySoft/Perfect-COpenSSL.git


그리고 xcodeproj를 다시 생성해 줍니다.

$ swift package generate-xcodeproj
$ open ./nGleServer006.xcodeproj/

xCode에서 main.swift파일을 열고 PerfectLib, PerfectHTTP, PerfectHTTPServer를 import한 후 build가 정상적으로 되는지 확인해 봅니다.

import PerfectLib
import PerfectHTTP
import PerfectHTTPServer

print("Hello, world!")

여기까지가 Perfect 기본 설치였습니다.

이제 webroot 폴더를 만들고 html 파일을 넣고 호출해 봅시다.

터미널에서 webroot 폴더를 만들고 html 파일을 하나 만들어 넣어 봅니다.

$ mkdir webroot
$ touch webroot/hello.html
$ swift package generate-xcodeproj
$ open ./nGleServer006.xcodeproj/

xCode에서 webroot 폴더와 hello.html 파일이 추가되었는지 확인합니다.

그리고 hello.html에 적당한 html문을 작성해 봅니다.

이제 main.swift로 이동해 server를 실행시켜 봅니다.

main.swift에서 print("Hello, world!")를 삭제하고 아래 코드를 추가합니다.

let server = HTTPServer()
server.serverPort = 8080
server.documentRoot = "webroot"

do {
    try server.start()
} catch PerfectError.networkError(let err, let msg) {
    print("Network error thrown: \(err) \(msg)")
}

xCode에서 실행과 할께 빌드된 서버를 실행시키려면 Edit Scheme에서 수정해 주면 됩니다.

Edit Scheme을 열고 Run에서 Options 탭을 클릭합니다. Working Directory를 체크하고 경로에 해당 프로젝트 폴더를 추가합니다.

제가 추가한 프로젝트 경로는 아래와 같습니다.

/Users/ngle/Documents/JakeWork/nGleServer006 

적용후 build 버튼을 클릭하면 빌드 후 서버 실행까지 진행됩니다.

브라우저를 얼고 http://localhost:8080/hello.html를 호출해 봅니다.

이제 request, response에 대한 처리를 해보겠습니다.

main.swift에 아래 코드를 추가합니다. 코드는 try server.start() 위에 추가합니다.

var routes = Routes()
routes.add(method: .get, uri: "/", handler: {
    request, response in
    response.setBody(string: "hello tongchun, you are at root directory with get.")
    .completed()
})
server.addRoutes(routes)

브라우저에 http://localhost:8080을 호출하면 추가한 string이 보이는지 확인합니다.

hello tongchun, you are at root directory with get.


이제 return 데이터를 json으로 넘겨줘 봅시다.

returnJSONMessage()라는 함수를 만들고 routes.add에 특정 method와 경로일 때 함수를 호출해 json 데이터를 리턴해 봅시다.

코드는 아래와 같습니다.

func returnJSONMessage(message: String, response: HTTPResponse) {
    do {
        try response.setBody(json: ["message": message])
        .setHeader(.contentType, value: "application/json")
        .completed()
    } catch {
        response.setBody(string: "Error handling request: \(error)")
            .completed(status: .internalServerError)
    }
}

routes.add(method: .get, uri: "/json", handler: {
    request, response in
    returnJSONMessage(message: "hello tongchun, you are at json directory with get.", response: response)
})

브라우저를 열고 http://localhost:8080/json을 호출해 봅니다.

아래와 같이 json 데이터가 리턴되는지 확인해 봅니다.

returnJSONMessage() 함수를 재활용해 다른 경로에서 json 데이터를 리턴해 봅시다.

아래 코드처럼 routes.add를 추가해 봅시다.

routes.add(method: .get, uri: "/json/second", handler: {
    request, response in
    returnJSONMessage(message: "you are at /json/second with get.", response: response)
})

브라우저에서 http://localhost:8080/json/second를 호출하면 지정한 json 데이터가 리턴됩니다.


이번에는 url 경로에서 paramater를 받아와 봅시다.

Perfect에서는 routers.add()의 uri에 {변수명}으로 path paramater를 지정할 수 있습니다.

경로를 이용해 name과 age를 받아오는 코드는 아래와 같습니다.

routes.add(method: .get, uri: "/json/{name}/{age}", handler: {
    request, response in
    guard let userName = request.urlVariables["name"], let userAge = request.urlVariables["age"] else {
        response.completed(status: .badRequest)
        return
    }
    returnJSONMessage(message: "Your name is \(userName) and age is \(userAge)", response: response)
})

브라우저에서 http://localhost:8080/json/tongchun/42를 호출하면 json 데이터로 리턴되게 됩니다.

get Method에서 query parameter로 전달하는 방법도 알아보자. query parameter는 경로 끝에 ?<key>=<value>&<key>=<value> 형태로 데이터를 전달하는 방식이다. request.queryParams로 데이터를 받는다.

받은 데이터는 튜플 리스트 형태이다. [(key, value), (key, value)] 이것을 for문으로 Dictionary에 넣어서 확인해 보자.

routes.add(method: .get, uri: "/queryparams", handler: {
    request, response in

    var paramDic = [String: String]()
    let parameters = request.queryParams

    for item: (String, String) in parameters {
        paramDic["\(item.0)"] = item.1
    }

    let userName = paramDic["name"]!
    let userAge = paramDic["age"]!
    returnJSONMessage(message: "Your name is \(userName) and age is \(userAge).", response: response)
})

브라우저를 열고 http://localhost:8080/queryparams?name=tongchun&age=42를 호출하면 json 데이터가 리턴된다.


이번에는 post방식으로 데이터를 받아와 봅시다.

post로 보낸 데이터는 request.param(name: <파라메터명>)으로 받는다. 파마메타로 name과 age를 보내고 json으로 리턴해보자

routes.add(method: .post, uri: "post", handler: {
    request, response in
    guard let name = request.param(name: "name"), let age = request.param(name: "age") else {
        response.completed(status: .badRequest)
        return
    }
    returnJSONMessage(message: "You sent me by post and data is \(name) / \(age)", response: response)
})

chrome 확장프로그램(Restlet Client)로 post 데이터를 전달하고 리턴된 데이터를 확인해보자.


마지막으로 post method로 json 데이터를 보내고 결과 값을 리턴받아 봅시다.

request.postBodyString으로 json 형식의 String 데이터를 넘길수 있습니다. 전달받은 json 형식의 String데이터를 JSon 데이터로 decoding해 처리할 수 있습니다. 아래 코드를 추가해서 확인해 봅니다.

routes.add(method: .post, uri: "/post/json", handler: {
    request, response in

    guard let jsonString = request.postBodyString else {
        response.completed(status: .badRequest)
        return
    }

    do {
        let jsonDic = try jsonString.jsonDecode() as! [String: String]
        let userName = jsonDic["name"]!
        let userAge = jsonDic["age"]!

        returnJSONMessage(message: "Your name is \(userName) and your age is \(userAge)", response: response)
    } catch {
        response.completed(status: .internalServerError)
        return
    }
})

실행하고 데이터를 넘기면 다음처럼 받아진다.

이상 Perfect 기본 기능 끝


Comments