티스토리 뷰

프로그래밍 공부/TIL : Rails Tutorial

Chapter 10 : Using Rails for API-only Applications

마음 따뜻한 개발자, 나른한 하루 2020. 7. 14. 11:41
이 글은 Rails 5.0 Guide 기준으로 작성됩니다.
https://guides.rubyonrails.org/v5.0/api_app.html

 

 

  • Using Rails for API-only Applications Intro

Ruby on Rails에는 API 역할만을 위한 Application이 생성되게 할 수 있습니다.

브라우저 기능을 배제한 채, middleware 설정 및 controller와 module 설정법에 대해 알아보겠습니다.

 

 

  • What is an API Application?

Rails를 "API"로 사용한다고 할 때, 웹 Application과 함께 프로그래밍 방식으로 액세스 가능한 API를 제공해야했습니다. 예를 들어 GitHub는 클라이언트에서 사용할 수 있는 API를 제공합니다.

 

많은 개발자들은 Rails를 사용하여 Web Application과 다른 기본 Application 간에 공유되는 백엔드를 구축하고 있습니다.

예를 들어 Twitter는 Web Application에서 공개 API를 사용하며,이 API는 JSON를 사용하는 정적 사이트로 구축됩니다.

 

Rails를 사용하여 form과 링크를 통해 서버와 직접 통신하는 HTML을 생성하는 대신, 많은 개발자들이 웹 애플리케이션을 JSON API를 활용하는 JavaScript를 통해 HTML로 제공되는 API 클라이언트로 취급하고 있습니다.

 

본문은 클라이언트 측 프레임 워크를 포함하여 API 클라이언트에 JSON 자원을 제공하는 Rails Application build에 대해 설명합니다.

 

 

  • Why Use Rails for JSON APIs?

Rails를 통해 JSON 구축에 있어, "Rails 기반으로 JSON을 구축하느니, 그보다 가벼운 Sinatra를 쓰는게 낫지 않나?" 라는 질문을 하곤 합니다. 매우 간단한 API 서버 개발에 있어선 맞을 수도 있습니다.

 

그럼에도 Rails를 사용하는 이유는 개발자가 많은 사소한 결정을 내리지 않고도 신속하게 시작하고 실행할 수있는 일련의 기본값을 제공하기 때문입니다.


Rails가 API Application에 기본적으로 제공하는 기능에 대해 살펴봅시다,

Middleware Layer에서 다룰 수 있는 것들은 아래와 같습니다.

 

1) Reloading

Rails Application은 transparent reloading을 지원합니다. Application이 커지고 모든 요청에 ​​대해 서버를 다시 시작해도 작동하지 않습니다.

 

2) Development Mode

Rails Application은 효율적인 개발시간을 가지게 합니다.

 

3) Test Mode

Ditto development mode.

 

4) Logging

Rails 애플리케이션은 모든 request을 현재 모드에 적합한 수준의 세부 정보와 함께 기록합니다. 개발중인 Rails 로그에는 요청 환경, 데이터베이스 Query 및 기본 성능 정보에 대한 정보가 포함됩니다.

 

5) Security

Rails는 IP 스푸핑 공격을 탐지 및 차단하고 타이밍 공격을 인식하는 방식으로 암호화 서명을 처리합니다.

 

6) Parameter Parsing

parameter에 있어 URL String 대신 JSON으로 request 해도 됩니다. Rails는 JSON을 디코딩하여 params로 제공합니다. 또한 중첩된 URL 인코딩 parameter을 사용해도 됩니다.

 

7) Conditional GETs

Rails는 조건부 GET (ETag 및 Last-Modified) request headers를 처리하고, response headers 및 상태 코드를 반환합니다. 오래된 것을 사용하기 만하면됩니다. 컨트롤러를 확인하면 Rails가 모든 HTTP 세부 정보를 처리합니다.

 

8) HEAD requests

Rails는 HEAD 요청을 GET 요청으로 투명하게(transparently) 변환 및 headers 만 반환합니다. 따라서 HEAD가 모든 Rails API에서 안정적으로 작동합니다.


기존에 있던 Rack Middleware와 관련해서 구축 할 수 있지만서도, 이 목록은 기본 JSON Middleware 스택이 'JSON만 생성' 하더라도 많은 값을 제공합니다.

Action Pack layer에서 다룰 수 있는 것들은 아래와 같습니다.

 

1) Resourceful Routing

RESTful JSON API를 빌드하는 경우, Rails Router를 사용할겁니다. HTTP와 컨트롤러의 매핑은 HTTP 측면에서 API를 모델링하는 방법에 대해 생각하는 데 시간을 들일 필요가 없음을 의미합니다.

 

2) URL Generation

라우팅의 반대는 URL 생성입니다. HTTP 기반의 좋은 API는 URL을 포함하는 겁니다. (예시는 GitHub Gist API 참조).

 

3) Header and Redirection Responses

헤더 추가에 있어, :no_contentredirect_to user_url(current_user) 이 편리합니다. 수동으로 response header을 추가 할 수 있지만, 굳이?...

 

4) Caching

Rails는 페이지, Action 및 fragment caching을 제공합니다. Fragment caching은 nested JSON 객체를 구축 할 때 특히 유용합니다.

 

5) Basic, Digest, and Token Authentication

Rails는 3가지 종류의 HTTP 인증을 지원합니다.

 

6) Instrumentation

Rails에는 작업 처리, 파일 또는 데이터 전송, redirection 및 데이터베이스 Query와 같은 다양한 이벤트가 등록된 handler를 트리거하는 instrumentation API가 있습니다. 각 이벤트의 payload에는 이벤트에 대한 정보가 제공됩니다. (작업 처리 이벤트의 경우 payload에는 컨트롤러, 작업, 매개 변수, 요청 형식, 요청 방법 및 요청의 전체 경로가 포함됨).

 

7) Generators

resource를 생성하고 추가 설정을 위해 단일 명령으로 Model, Controller, test stubs 및 Routes를 생성하는 것이 종종 나을 때도 있습니다. Migration 및 기타의 경우 동일합니다.

 

8) Plugins

많은 타사 라이브러리에는 Rails가 지원되므로 라이브러리와 웹 프레임 워크를 연동설정 함으로서 비용을 줄일 수 있습니다. (기본 generator 재정의(overriding), Rake tasks 추가 및 logger과 cache 백엔드와 같은 Rails 기능 선택)


물론 Rails boot process는 등록 된 모든 component를 연결합니다. 예를 들어 Rails boot process는 Active Record를 구성 할 때  config/database.yml  파일을 사용하는 Process입니다.

 

 

  • The Basic Configuration

가장 먼저 API 서버가 될 Rails 애플리케이션을 구축하는 경우 더 제한된 Rails 서브 세트로 시작하여 필요에 따라 기능을 추가 할 수 있습니다.

 

1. Creating a new application

rails new my_api --api

터미널에서 위 명령어를 통해 API 기능에 집중된 레일즈 프로젝트를 생성할 수 있습니다.

--api 옵션 기반으로 제작된 프로젝트는 아래와 같은 작업이 진행됩니다 :

  • 기존보다 더 제한된 Middleware 세팅으로 Application 설정이 됩니다. 특히 쿠키 지원 등 Browser Application에 유용히 쓰였던 middleware은 포함되지 않습니다.
  • 과거 ApplicationController은 ActionController::Base에서 상속되서 쓰이던 방식과 달리, API 옵션에서는 ActionController::API을 상속받아 씁니다. Middleware와 마찬가지로, 브라우저 애플리케이션에서 주로 사용하는 기능을 제공하는 모든 ActionController 모듈을 제외합니다.
  • views, helper, assets 생성이 생략됩니다.

 

2.  Changing an existing application

기존의 Rails Application을 API Application으로 변경을 하려면, 아래 단계를 참고해 주세요 :

1.  config/application.rb  에서 Application 클래스 정의 맨 위에 다음 행을 추가하세요.

config.api_only = true

 

2.  config/environments/development.rb  에서 config.debug_exception_response_format 을 설정 후, 개발 모드에서 오류가 발생 시, response에 사용되는 형식을 설정해주세요.

2-1) 디버깅 정보가 포함 된 HTML 페이지를 렌더링하려면 :default 옵션을 사용하세요.

config.debug_exception_response_format = :default

 

2-2) response format을 유지하는 디버깅 정보를 렌더링하려면 :api 옵션을 사용하세요.

config.debug_exception_response_format = :api

config.api_only = true 로 설정되면 기본적으로 config.debug_exception_response_format :api 로 설정됩니다.

 

3. 마지막으로  app/controllers/application_controller.rb  에서 상속 class을 변경해주면 됩니다.

# from (변경 전)
class ApplicationController < ActionController::Base
end

# to (변경 후)
class ApplicationController < ActionController::API
end

 

 

  • Choosing Middleware

API 애플리케이션은 기본적으로 다음 Middleware와 함께 제공됩니다.

Rack::Sendfile
ActionDispatch::Static
ActionDispatch::Executor
ActiveSupport::Cache::Strategy::LocalCache::Middleware
Rack::Runtime
ActionDispatch::RequestId
Rails::Rack::Logger
ActionDispatch::ShowExceptions
ActionDispatch::DebugExceptions
ActionDispatch::RemoteIp
ActionDispatch::Reloader
ActionDispatch::Callbacks
Rack::Head
Rack::ConditionalGet
Rack::ETag

 

위 Middleware에 대한 설명은 여기를 참고해주세요.

 

Active Record를 포함한 다른 플러그인에도 Middleware를 추가 할 수 있습니다. 이러한 Middleware는 build중인 Application 유형에 관계없이 API 전용 Rails 애플리케이션에 적합합니다.

 

Application이 어떤 Middleware을 가지고 있는지에 대해선 아래 명령어를 통해 확인할 수 있습니다.

rails middleware

 

1. Using the Cache Middleware

기본적으로 Rails는 Application configuration에 따라 캐시 저장소를 제공하는 Middleware를 추가합니다. (default: memcache)

 

stale? 메소드 호출은 request쪽 header에 있는 If-Modified-Since와 @post.updated_at와 비교합니다. header가 마지막으로 수정 된 것보다 최신 인 경우, 이 작업은 "304 Not Modified" 응답을 반환합니다. 그렇지 않으면 응답을 보여주고, Last-Modified header를 가지고 있게 됩니다.

브라우저에서 json 서버에 request/response 시 보여지는 Headers

 [Dash] stable?  response에서 etag 및(또는) last_modified를 설정하고, 클라이언트의 request와 비교하여 확인합니다.

요청이 제공된 option과 일치하지 않으면 요청이 오래된 것으로 간주되어 새로 생성됩니다.

def show
  @post = Post.find(params[:id])
 
  if stale?(last_modified: @post.updated_at)
    render json: @post
  end
end

일반적으로 이 메커니즘은 클라이언트 별로 사용됩니다.

 

또한 아래와 같이 public 옵션을 추가 후 Cache Middleware을 사용하면 클라이언트 간 이 캐싱 메커니즘을 공유 할 수 있습니다.

def show
  @post = Post.find(params[:id])
 
  if stale?(last_modified: @post.updated_at, public: true)
    render json: @post
  end
end

이는 Cache Middleware가 Rails Cache에서 URL의 Last-Modified 값을 저장하고 동일한 URL에 대한 후속 인바운드 요청에 If-Modified-Since 헤더를 추가 함을 의미합니다.

 

HTTP 시맨틱을 사용하는 페이지 캐싱으로 생각하면 됩니다.

 

 

2. Using Rack::Sendfile

Rails Controller에서 send_file 메소드를 사용하면 X-Sendfile 헤더가 설정됩니다. Rack::Sendfile은 파일을 전송합니다.

프론트-엔드 서버가 파일 전송이 가속화 되는 경우, Rack::Sendfile은 실제 파일 전송 작업을 프론트-엔드 서버로 오프로드(offload) 합니다.

 

Environment의 구성 파일에서 프론트-엔드 서버가 config.action_dispatch.x_sendfile_header 설정을 통해 header 이름을 구성 할 수 있습니다. (더 자세한 내용은 the Rack::Sendfile documentation 참고)

 

다음은 많이 사용되는 서버(Apache, lighttpd, Nginx)를 구성 후, 파일 전송 가속화를 위한 설정값입니다.

# Apache and lighttpd
config.action_dispatch.x_sendfile_header = "X-Sendfile"
 
# Nginx
config.action_dispatch.x_sendfile_header = "X-Accel-Redirect"

Rack::Sendfile document에 따라 서버를 설정하세요.

 

3. Using ActionDispatch::Request

ActionDispatch::Request#params 는 클라이언트로 부터 JSON 형식을 parameters를 변환 후, controller에서 params를 사용할 수 있게합니다.

 

이를 사용하기 위해 클라이언트가 JSON 인코딩 parameters로 요청하고, Content-Type = application/json 로 지정해야합니다.

아래 jquery 코드를 예로 들어보면 :

jQuery.ajax({
  type: 'POST',
  url: '/people',
  dataType: 'json',
  contentType: 'application/json',
  data: JSON.stringify({ person: { firstName: "Yehuda", lastName: "Katz" } }),
  success: function(json) { }
});

ActionDispatch::Request 에 Content-Type이 표시되고 parameters는 다음과 같습니다.

{ :person => { :firstName => "Yehuda", :lastName => "Katz" } }

 

4. Other Middleware

Rails는 특히 API 클라이언트 중 하나가 브라우저인 경우 API 애플리케이션에서 사용할 수 있는 여러 Middleware를 제공합니다.

Rack::MethodOverride
ActionDispatch::Cookies
ActionDispatch::Flash

# For sessions management
ActionDispatch::Session::CacheStore
ActionDispatch::Session::CookieStore
ActionDispatch::Session::MemCacheStore

위에 명시된 Middleware은 아래와 같이 추가해내면 됩니다.

config.middleware.use Rack::MethodOverride

 

5. Removing Middleware

API 전용 Middleware이 기본적으로 가진 Middleware를 사용하지 않으려면 아래와 같이 코드를 추가해서 제거 할 수 있습니다.

config.middleware.delete ::Rack::Sendfile

특정 미들웨어를 제거하면 Action Controller에서는 더이상 Middleware가 가진 기능을 지원하지 않습니다.

 

 

  • Choosing Controller Modules

API Application(ActionController::API)을 활용하는 Rails Project의 Controller에는 아래 Module들이 기본으로 지원됩니다. :

  • ActionController::UrlFor  url_for 및 그와 유사한 url 헬퍼를 사용할 수 있게 합니다.
  • ActionController::Redirecting  redirect_to 문법을 지원합니다.
  • AbstractController::Rendering and ActionController::ApiRendering  rendering을 지원합니다.
  • ActionController::Renderers::All  render :json 및 그와 관련된 기능을 지원합니다.
  • ActionController::ConditionalGet  stale? 문법을 지원합니다.
  • ActionController::BasicImplicitRender  응답이 없을 경우, response가 empty로 반환합니다.
  • ActionController::StrongParameters  Active Model 할당 및 parameters에 대한 화이트리스트를 지원합니다.
  • ActionController::ForceSSL  force_ssl을 지원합니다.
  • ActionController::DataStreaming  send_file 및 send_data을 지원합니다.
  • AbstractController::Callbacks  before_action 와 유사한 Filter을 지원합니다.
  • ActionController::Rescue  rescue_from 문법을 지원합니다.
  • ActionController::Instrumentation  Action Controller에 의해 정의 된 instrumentation hooks 지원 (the instrumentation guide 문서 참고)
  • ActionController::ParamsWrapper  parameters hash를 중첩 해시로 감싸므로 POST 요청을 보내는 root elements를 정할 필요가 없습니다.

 

다른 플러그인 또한 Module을 추가 할 수 있습니다.

Rails console에서 ActionController::API에 포함 된 모든 모듈 목록을 확인해볼 수 있습니다.

## Rails Console 입력
ActionController::API.ancestors - ActionController::Metal.ancestors

# =>
=> [ActionController::API, ActiveRecord::Railties::ControllerRuntime, ActionDispatch::Routing::RouteSet::MountedHelpers, ActionController::ParamsWrapper, ActionController::Instrumentation, ActionController::Rescue, ActionController::DataStreaming, ActionController::ForceSSL, AbstractController::Callbacks, ActiveSupport::Callbacks, ActionController::StrongParameters, ActiveSupport::Rescuable, ActionController::BasicImplicitRender, ActionController::ConditionalGet, ActionController::Head, ActionController::Renderers::All, ActionController::Renderers, ActionController::Rendering, ActionController::ApiRendering, ActionController::Redirecting, ActiveSupport::Benchmarkable, AbstractController::Logger, ActionController::UrlFor, AbstractController::UrlFor, ActionDispatch::Routing::UrlFor, ActionDispatch::Routing::PolymorphicRoutes, AbstractController::Rendering, ActionView::ViewPaths]

 

1. Adding Other Modules

모든 Action Controller Module은 종속된 Module에 대해 알고 있으므로 Controller에 Module을 자유롭게 포함시킬 수 있으며 모든 종속 관계에 대해서도 설정 및 포함됩니다.

 

일부 공통 Module에 대해서는 아래와 같이 추가되어 있습니다 :

  • AbstractController::Translation  번역(translate) 메소드 지원
  • ActionController::HttpAuthentication::Basic (or Digest or Token)  basic, digest or token HTTP 인증을 지원합니다.
  • ActionView::Layouts  페이지가 렌더링 시 보여질 layouts에 대해 지원합니다.
  • ActionController::MimeResponds  respond_to 문법을 지원합니다.
  • ActionController::Cookies  서명 및 보안처리 된 cookies를 지원합니다. 해당 Module은 cookies Middleware가 이용되어야 합니다.

Module을 추가하는 가장 좋은 위치(파일)는 ApplicationController 이지만, 개별 컨트롤러에도 Module을 추가 할 수 있습니다.

 

 

  • 자료 참고

1. Speed Things up by Learning about Caching in Rails

 

 

댓글
댓글쓰기 폼
공지사항
Total
44,670
Today
11
Yesterday
141
링크
«   2020/09   »
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30      
글 보관함