티스토리 뷰
[Rails][Web API] Post 요청 처리하기
웹 API 제작을 하는 관점에서 레일즈에서 응답코드를 넣어 반응하는 것이 클라이언트에서 처리를 할 때도 용이하고 바람직합니다.
앞 전 게시글에서 JSON 혹은 XML로의 응답에 대해 다루어 보았습니다. 이번에는 Post, Put, Patch 그리고 Delete 중 Post의 처리 방법을 살펴보겠습니다.
POST METHOD 처리
POST 처리 시에 201 HTTP 응답코드를 이용하는 것이 바람직합니다. 201 상태응답은 다음과 같습니다:
201 Created
새로운 URI가 만들어질 때마다 사용되며 결과 코드와 함께 새로운 데이터가 위치한 곳을 지정하기 위해 Location 헤더가 서버에 의해 주어집니다. 원 서버는 201 상태 코드를 리턴하기 전에 반드시 자원을 생성해야 합니다. 처리가 즉각적으로 수행될 수 없을 때에 서버는 202(Accept) 응답으로 대신 응해야합니다.
다음으로 201 상태코드에 맞는 예제코드를 살펴보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | class EpisodesController < ApplicationController def create episode = Episode.new(episode_params) if episode.save render json: episode, status: 201, location: episode end end private def episode_params params.require(:episode).permit(:title, :description) end end | cs |
status: 201 대신에 status: :created 를 사용하도 됩니다. location: 부분에 예제와 같이 해당 리소스의 url을 넣으면 됩니다.
하지만 이대로 사용을하면 레일즈의 FORGERY PROTECTION 때문에 422 (Unprocessable Entity) 응답이 옵니다. 이를 해결하기 위해서는 application_controller.rb를 다음과 같이 수정해줘야 합니다.
app/controllers/application_controller.rb
1 2 3 4 5 6 | class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. # protect_from_forgery with: :exception protect_from_forgery with: :null_session end | cs |
이렇게 수정하면 POST 요청이 오면 authenticity token 을 무시하고 세션을 사용하지 않게 됩니다. 정상적으로 생성이 되게 됩니다.
다음과 같이 리눅스 계열의 curl 명령어로 테스트해볼 수 있습니다.
$ curl -i -X POST -d 'episode[title]=test' http://localhost:3000/episodes
body 없이 응답하기
만약, 속도 상의 문제로 응답의 body 부분 없이 반응 하려면 204 HTTP 응답코드를 사용하시면 됩니다. 이 경우 head 함수를 이용하여 처리할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class EpisodesController < ApplicationController def create episode = Episode.new(episode_params) if episode.save head 204, location: episode end end private def episode_params params.require(:episode).permit(:title, :description) end end | cs |
head 204 는 head :no_content 로도 사용할 수 있습니다.
예외처리하기
예외 처리는 422 응답코드를 이용하여 처리하면됩니다.
1 2 3 4 | # app/models/episode.rb class Episode < ActiveRecord::Base validates :title, presence: true end | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class EpisodesController < ApplicationController def create episode = Episode.new(episode_params) if episode.save render json: episode, status: :created, location: episode else render json: episode.errors, status: 422 end end private def episode_params params.require(:episode).permit(:title, :description) end end | cs |
서버 내부의 에러의 경우 레일즈에서 500 에러응답을 자동으로 처리해줍니다.