본문 바로가기

백앤드

Vapor - Routing + JSON Response

이번 글에서는 Vapor에서 다루는 Routing에 대해서 다뤄보고자 한다. 그리고 어쨌든 앱에서 받아야 할 데이터는 JSON형식의 데이터를 받아야 하니까 기본 JSON Response를 반환하는 것을 목표로 해보고자 한다.

 

HTTP Request를 보낼 때는 여러 Method를 이용하여 보내게 된다. 크게 GET, POST, PUT, PATCH, DELETE 등이 존재한다. 일반적으로 해당 요청을 통해 수행하게 될 CRUD(Create, Read, Update, Delete) 작업에 따라 적절한 Method를 골라서 사용하면 된다.

 

당연히 Vapor에서도 이러한 기능을 제공하고 있다고 한다. 이번 글에서는 당장 데이터를 처리(생성 삭제 수정 등)할 게 없으니 GET 리퀘스트만을 날려보고 Response로 JSON형식의 문자열을 반환받도록 해보자.

 

Request 구성

- Method: GET

- URL: http://127.0.0.1:8080/api/sample

Response 구성

- Status Code: 200 OK

- Content Type: application/json

- body:

{
    status : "success",
    data : {
        "posts" : [
            { "id" : 1, "title" : "A blog post", "body" : "Some useful content" },
            { "id" : 2, "title" : "Another blog post", "body" : "More content" },
        ]
     }
}

위와 같은 Request와 Response를 어떻게 처리할지 한번 살펴보자.

 

1. Request 생성하기

Sources/App/routes.swift 기본 코드

먼저 기존 routes.swift에 작성된 코드를 보니 처음 http://127.0.0.1:8080에서 노출되었던 "It works!"가 여기에서 문자열을 반환하고 있음을 알 수 있었다. 추가로 하단에 hello인 것을 보아 http://127.0.0.1:8080/hello/ 경로로 진입하면 "Hello, world!" 문자열을 페이지에서 출력하고 있을 것 같았다. 

/hello/ path에 접근했을 때의 화면

예상대로 "Hello, world!를 출력하고 있다. 

그럼 우리가 원하는 /api/sample 에 대한 경로 설정을 어떻게 해야 할까.. 하고 보니 아래와 같은 메소드 설명을 볼 수 있었다.

get(_:use:) 메소드 설명

path값을 여러 개 전달할 수 있는 걸 보니 get("api", "sample") { req async in ~~~ } 같은 방식으로 사용하면 될 것 같다.

/api/sample 경로 추가

위처럼 경로를 추가해 주고 접속해 보면

/api/sample path에 접근했을 때의 화면

원하는 결괏값을 반환한 것을 확인할 수 있다.

2. Response 생성하기

이제 우리가 원래 원했었던 JSON 데이터를 반환하도록 코드를 수정해 보자.

업데이트된 Response

"This is api/sample response" 문자열을 JSON 문자열로 변경하여 반환하니 원래 원하던 데이터를 받아볼 수 있었다.

여기까지는 괜찮은데 실제로 Response가 어떻게 내려오는지 살펴보니...

Response Header Field

우리가 원하던 것처럼 Conteont-Type이 application/json이 아닌 text/plain으로 내려오고 있었다. 

 

마지막으로 Content-Type을 어떻게 수정해야 할지 살펴보자.

 

다시 한번 get 메소드를 자세히 살펴보니 아래와 같이 Response를 반환할 수 있다고 나와있다.

RoutesBuilder의 get 메소드

하단의 where절을 보면 Response타입이 AsyncResponseEncodable을 따르도록 되어있다.

 

다시 AsyncResponseEncodable타입을 따라가 보면

AsyncResponseEncodable 프로토콜

해당 프로토콜을 채택하기 위해서는 encodedResponse(for:) 메소드를 구현해 주면 된다고 한다.

 

그럼 반환하고자 하는 데이터 모델(Post)을 먼저 만들어보자면 필요한 필드는 id: Int, title: String, body: String 정도로 구성할 수 있다. 

그럼 위와 같이 Post 구조체를 만들 수 있는데, 이제 이 구조체에 대한 배열을 JSON으로 반환하도록 Encodable 프로토콜을 채택하고, PostResponse 구조체를 만들어 인코딩할 수 있도록 하면 될 것 같다.

 

PostResponse에 AsyncResponseEncodable를 채택하도록 하니 encodedResponse(for:) 메소드를 구현해야 한다고 한다. 

리턴값(Response)의 이니셜라이저를 보니 status, version, headerNoUpdate, body를 받고 있다.

- status는 ok(200)을

- version은 1.1(또는 2.0)을

- headersNoUpdate에는 contentType을 명시해 주면 될 것 같은데 왜 이름이 noUpdate인지는 나중에 확인이 필요해 보인다.

- body에는 구조체 배열에 대한 JSON 값을 넣어주면 될 것 같다.

self(PostResponse)를 인코딩해서 반환하도록 함.

위처럼 PostResponse 자체를 JSONEncoder를 통해 인코딩 후 데이터를 body에 전달하도록 하면 여기서의 작업은 마무리된 것 같다.

 

마지막으로 routes에서 아래와 같이 코드를 수정하면

routes.swift 코드 수정

아래와 같이 127.0.0.1:8080/api/sample 접속 시 아래처럼 Response가 표시된 것을 확인할 수 있다.

json데이터가 정상적으로 출력되는 것과 더불어 처음 목표했던 것과 같이 Content Type이 application/json으로 잘 내려온 것을 확인할 수 있다.


간단한 Response를 JSON으로 반환하는데 생각보다 채택하고 확인해야 할 코드들이 많았다. 다음 글에서는 기본 Response에 대한 틀을 만들어보고 로그인 로직을 한번 만들어보면 좋을 것 같다.

'백앤드' 카테고리의 다른 글

Vapor - 로그인 구현하기  (0) 2024.02.03
Vapor - 프로젝트 기본 구성  (1) 2024.01.22
Vapor - 시작하기(기본 프로젝트 생성)  (1) 2024.01.22