don't stop believing

Web 서버 기본 구성 1 (기본 구성과 mustache 확인) 본문

Swift/Perfect

Web 서버 기본 구성 1 (기본 구성과 mustache 확인)

Tongchun 2018. 6. 18. 18:20

API 서버와 Front End를 담당하는 Web 서버를 구분해서 개발하려고 합니다.

이번엔 Web (Front End) 서버의 기본 구성을 잡아볼까 합니다.


기본 구성은 Perfect로 서버를 띄우고 API 서버에 호출해 데이터를 받아오는 부분과 Mustache로 Web 화면을 구성하는 부분을 작성해 보겠습니다.


먼저 기본 Swift Package 를 초기화 해줍니다.

$ mkdir nGleServer002
$ cd nGleServer002
$ swift package init --type executable
$ open Package.swift

swift package에서 dependencies를 잡아주기 위해 Package.swift 파일을 엽니다.

그리고 아래와 같이 Perfect-HTTPServer, Perfect-Mustache, Perfect_CURL을 추가합니다.

// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "nGleServer002",
    dependencies: [
        .package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", from: "3.0.0"),
        .package(url: "https://github.com/PerfectlySoft/Perfect-Mustache.git", from: "3.0.0"),
        .package(url: "https://github.com/PerfectlySoft/Perfect-CURL.git", from: "3.0.0")
    ],
    targets: [
        .target(
            name: "nGleServer002",
            dependencies: ["PerfectHTTPServer","PerfectMustache", "PerfectCURL"]),
    ]
)

Package.swift 파일을 저장하고 라이브러리들을 다운받기 위해 swift package update를 해줍니다.

그다음 정상적으로 빌드가 되는지 swift build도 해줍니다.

$ swift package update
$ swift build

build까지 문제가 없다면 controller와 handler구성을 잡을 차례입니다.

그 전에 Web 페이지에 사용될 Static 파일들을 정리할 Webroot 폴더를 만들어 주겠습니다.

Webroot 폴더는 프로젝트의 root 디렉토리에 만들어 줍니다.

$ mkdir Webroot

이제 main.swift가 있는 위치에서 controller.swift와 handler.swift 파일을 만들어 줍니다.

$ cd Sources/nGleServer002/
$ touch controller.swift
$ touch handler.swift

handler를 먼저 만들겠습니다.

handler.swift 파일을 열고 아래와 같이 작성합니다.


처음에는 필요한 라이브러리들을 import해줍니다.

그리고 MustachePageHandler를 상속받은 MustacheHelper라고 이름진 Struct(구조체)를 만들어 줍니다.


그리고 handler 클레스를 만들어 줍니다.

handler 클레스 안에는 우선 getSamplePage라는 함수를 만들어 줍니다. 이 함수는 Webroot폴더에 있는 sample.mustache라는 파일을 html로 parsing해 request로 전달합니다.

import Foundation
import PerfectLib
import PerfectHTTP
import PerfectHTTPServer
import PerfectMustache

struct MustacheHelper: MustachePageHandler {
    var values: MustacheEvaluationContext.MapType

    func extendValuesForResponse(context contxt: MustacheWebEvaluationContext, collector: MustacheEvaluationOutputCollector) {
        contxt.extendValues(with: values)
        do {
            try contxt.requestCompleted(withCollector: collector)
        } catch {
            let response = contxt.webResponse
            response.appendBody(string: "\(error)")
                .completed(status: .internalServerError)
        }
    }
}

class Handler {

    func getSamplePage(request: HTTPRequest, response: HTTPResponse) {

        let values = MustacheEvaluationContext.MapType()
        let mustachHandler = MustacheHelper(values: values)
        let webPath = request.documentRoot + "/sample.mustache"

        mustacheRequest(request: request, response: response, handler: mustachHandler, templatePath: webPath)
    }
}

이제 controller.swift 파일을 열고 Route를 잡아 줍니다.

get method를 사용하고 uri는 /sample 입니다. 이건 위에서 만든 Handler 클레스의 getSamplePage와 연결합니다.

import Foundation
import PerfectLib
import PerfectHTTP
import PerfectHTTPServer

final class Controller {

    let sample = Handler()

    var routes: [Route] {
        return [
            Route(method: .get, uri: "/sample", handler: sample.getSamplePage)
        ]
    }
}

이제 main.swift 차례입니다. main.swift 파일에서 perfect서버의 포트와 Route를 지정합니다.

import Foundation
import PerfectLib
import PerfectHTTP
import PerfectHTTPServer

let server = HTTPServer()
let controller = Controller()

server.serverPort = 8080
server.documentRoot = "Webroot"
server.addRoutes(Routes(controller.routes))

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

마지막으로 Handler 클레스에서 언급했던 /sample.mustache 파일을 만들 차례입니다.

프로젝트 Root Directory에 만들었던 Webroot 폴더안에 sample.mustache라고 파일을 만들어 줍니다. 그리고 아래와 같이 html 테그를 작성합니다.

<html>
    <header>
        <title>nGle Sample</title>
    </header>
    <body>
        <h1>nGle Sample</h1>
    </body>
</html>

이제 build를 하고 html페이지가 나오는지 /gample을 호출해 봅시다.

$ swift build
$ ./.build/x86_64-apple-macosx10.10/debug/nGleServer002
[INFO] Starting HTTP server  on 0.0.0.0:8080

서버가 실행되었다면 http://localhost:8080/sample 페이지를 호출해 봅니다.


여기까지 잘 따라 오셧다면 이제 mustache에 데이터를 넣고 동적인 html페이지를 만들어 보겠습니다.


Handler 클래스의 getSamplePage() 함수를 그대로 사용해 봅시다.

함수 안에 let values = MustacheEvaluationContext.MapType() 를 정수(let)이 아닌 변수(var)로 선언합니다.

그리고 MustacheEvaluationContext.MapType()을 초기화한 values 변수에 Key Value 형태로 아래와 깉이 추가해 줍니다.

func getSamplePage(request: HTTPRequest, response: HTTPResponse) {

    var values = MustacheEvaluationContext.MapType()
    values["name"] = "Tongchun"
    values["depart"] = "플랫폼QA실"
    values["favorites"] = [
        ["fovorite": "Swift"],
        ["fovorite": "Python"],
        ["fovorite": "ML"],
        ["fovorite": "Unity"],
        ["fovorite": "automation testing"]
    ]

    let mustachHandler = MustacheHelper(values: values)
    let webPath = request.documentRoot + "/sample.mustache"

    mustacheRequest(request: request, response: response, handler: mustachHandler, templatePath: webPath)
}

이버에는 sample.mustache파일로 가서 아래와 같이 수정합니다.

<html>
    <header>
        <title>nGle Sample</title>
    </header>
    <body>
        <h1>nGle Sample</h1>
        <h3>{{name}}</h3>
        <h3>{{depart}}</h3>
        <ul>
        {{#favorites}}
            <li>{{fovorite}}</li>
        {{/favorites}}
        {{^favorites}}
            <li>No favorites :(</li>
        {{/favorites}}
        </ul>
    </body>
</html>

그리고 다시 swift build 하고 빌드 파일을 실행해 줍니다.

$ swift build && ./.build/x86_64-apple-macosx10.10/debug/nGleServer002
Compile Swift Module 'nGleServer002' (3 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/nGleServer002
[INFO] Starting HTTP server  on 0.0.0.0:8080

서버가 실행되었다면 http://localhost:8080/sample를 열어봅니다.

values 변수에 추가한 내용이 mustache를 통해 html 페이지로 잘 보이고 있습니다.


다음으로 API 서버에서 데이터를 불러와 Web 서버의 html페이지에 뿌려주는 예제를 해보겠습니다.


Comments