From fc74f55b0bcdec09f24de340ba772c61cfadd343 Mon Sep 17 00:00:00 2001 From: Shia <rise.shia@gmail.com> Date: Tue, 30 Aug 2016 17:53:49 +0900 Subject: [PATCH] Translate Api app --- source/ko/api_app.md | 335 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 source/ko/api_app.md diff --git a/source/ko/api_app.md b/source/ko/api_app.md new file mode 100644 index 0000000000000..4cd3f1f082d22 --- /dev/null +++ b/source/ko/api_app.md @@ -0,0 +1,335 @@ +API 전용 레일스 애플리케이션 만들기 +===================================== + +이 가이드의 내용: + +* 레일스가 API 전용 애플리케이션을 위해 제공하는 기능 +* 브라우저 관련 기능을 제외하고 레일스를 실행하기 +* 미들웨어 선택하기 +* 컨트롤러에서 사용할 모듈 선택하기 + +-------------------------------------------------------------------------------- + +API 애플리케이션에 대해 +--------------------------- + +지금까지 레일스로 API를 사용한다고 하면 프로그램이 사용할 수 있는 API를 웹 애플리케이션에 추가하는 방식을 의미했습니다. +예를 들어 GitHub이 제공하는 [API](http://developer.github.com)를 직접 만든 클라이언트에서 사용할 수 있습니다. + +클라이언트 프레임워크의 등장에 따라, 다른 웹 애플리케이션과 네이티브 애플리케이션에서 레일스로 만든 +백엔드 서버를 사용하는 경우가 늘었습니다. + +Twitter는 자사 웹 애플리케이션에서 [공개 API](https://dev.twitter.com)를 사용하고 있습니다. +이 웹 애플리케이션은 JSON 리소스만을 사용하는 정적인 사이트입니다. + +많은 개발자가 레일스를 폼이나 링크를 통하는 서버 간의 통신을 위해 HTML을 생성하는 대신, +웹 애플리케이션을 단순한 API 클라이언트로 정의하고, JSON API를 사용하는 HTML과 자바스크립트를 제공하는 +방식으로 다루게 되었습니다. + +여기에서는 클라이언트 프레임워크의 설명을 포함해, JSON 리소스를 API 클라이언트에 제공하는 레일스 +애플리케이션을 구축하는 방법에 관해서 설명합니다. + +JSON API에 레일스를 사용하는 이유 +---------------------------- + +레일스로 JSON API를 만드는 것에 대해서 많은 개발자가 가장 먼저 떠올리는 질문은 이렇습니다. +"레일스로 JSON을 제공하는건 너무 거창하지 않나요? 그냥 Sinatra로 만들면 어떤가요?" + +단순한 API 서버라면 아마도 그럴 겁니다. 하지만 HTML의 비중이 매우 큰 애플리케이션이라도, 로직 대부분은 +뷰 레이어가 아닌 곳에 존재합니다. + +많은 개발자가 레일스를 채용하는 이유는 세세한 설정을 고민하지 않고, +빠르게 애플리케이션을 제공할 수 있기 때문입니다. + +API 애플리케이션 개발에 도움이 되는 레일스의 기능을 몇 가지 소개합니다. + +미들웨어에서 제공하는 기능 목록 + +- 리로딩: 레일스 애플리케이션은 '투명한 리로딩'을 지원합니다. 예를 들어 애플리케이션이 커져 요청마다 서버를 재기동하는 방법을 사용할 수 없더라도 투명한 리로딩이 가능합니다. +- 개발 모드: 레일스 애플리케이션의 개발 모드에는 기본값이 이미 설정되어 있으므로 실제 환경의 성능에 대한 걱정 없이 즐겁게 작업을 진행할 수 있습니다. +- 테스트 모드: 개발 모드와 같습니다. +- 로그 출력: 레일스 애플리케이션은 요청마다 로그를 출력합니다. 또한 현재 모드에 따라서 로그의 레벨이 조정됩니다. 개발 모드의 로그에는 요청 환경, 데이터베이스 질의, 간단한 성능 정보 등이 출력됩니다. +- 보안: [IP 스푸핑 공격](https://en.wikipedia.org/wiki/IP_address_spoofing)을 검출, 방어합니다. 또한 [타이밍 공격](http://en.wikipedia.org/wiki/Timing_attack)에 대응할 수 있는 암호화 서명을 다룹니다. +- 매개변수 분석: URL 인코딩이나 문자열 대신 JSON으로 매개변수를 지정할 수 있습니다. JSON은 레일스에서 해석되어 `params`를 통해 접근할 수 있습니다. 물론 중첩된 URL 인코딩 매개변수도 다룰 수 있습니다. +- 조건부 GET: 레일스에서는 `ETag`나 `Last-Modified`를 사용한 조건부 GET을 사용합니다. 이는 요청 헤더를 처리하고, 올바른 응답 헤더와 상태 코드를 돌려줍니다. 컨트롤러에 [`stale?`](http://api.rubyonrails.org/classes/ActionController/ConditionalGet.html#method-i-stale-3F)을 추가하면 HTTP의 구체적인 동작은 레일스가 처리합니다. +- HEAD 요청: 레일스에서는 `HEAD` 요청을 투명하게 `GET` 요청으로 변환하고, 헤더만을 반환합니다. 이를 통해서 모든 레일스 API에서 `HEAD` 요청을 사용할 수 있습니다. + +Rack 미들웨어의 이런 기능들을 직접 구현할 수도 있습니다만, 레일스의 기본 미들웨어를 "JSON 생성용"으로 +쓰더라도 많은 이점을 얻을 수 있습니다. + +액션 팩에서 제공하는 기능 + +- 리소스 기반 라우팅: RESTful JSON API를 개발한다면 레일스의 라우터도 사용하고 싶을 것입니다. HTTP로부터 컨트롤러로 명확하게 연결할 수 있으므로 HTTP에 대해서 API를 어떻게 구성할지 고민할 필요가 없습니다. +- URL 생성: 라우팅은 URL을 생성할 때에도 편리합니다. 잘 구성된 HTTP 기반의 API에는 URL도 포함됩니다([GitHub Gist API](http://developer.github.com/v3/gists/)가 좋은 예시입니다). +- 헤더 응답이나 리다이렉션 응답: `head :no_content`나 `redirect_to user_url(current_user)` 등을 사용할 수 있습니다. 헤더 응답을 직접 생성하지 않아도 됩니다. +- 캐시: 레일스는 페이지 캐싱, 액션 캐싱, 조각 캐싱을 사용할 수 있습니다. 특히 조각 캐싱은 중첩된 JSON 객체를 만들 때 유용합니다. +- 기본 인증, 다이제스트 인증, 토큰 인증: 3종류의 HTTP 인증을 간단하게 도입할 수 있습니다. +- 계측(Instrumentation): 레일스의 계측 API는 등록한 다양한 이벤트 핸들러를 실행합니다. 액션 처리, 파일이나 데이터 전송, 리다이렉트, 데이터베이스 질의 등을 다룹니다. 각 이벤트의 페이로드에 다양한 정보가 포함되어 있습니다. 예를 들어 이벤트를 처리하는 액션의 경우, 페이로드에는 컨트롤러, 액션, 매개변수, 요청 형식, 요청 경로등이 포함됩니다. +- 제너레이터: 명령 하나로 리소스를 간단하게 생성하고, API에 맞는 모델, 컨트롤러, 테스트 스텁, 라우팅을 바로 사용할 수 있습니다. 마이그레이션 등의 작업도 명령으로 실행할 수 있습니다. +- 플러그인: 수많은 서드파티 라이브러리를 사용할 수 있습니다. 라이브러리 설정이나 웹 프레임워크 등의 연동도 간단하므로, 비용을 줄일 수 있습니다. 플러그인을 통해 기존 제너레이터를 덮어쓰거나 Rake 태스크를 추가, 또는 레일스의 동작을 변경할 수도 있습니다(로거나 캐시 백엔드 등). + +물론 레일스의 실행 프로세스에서는 등록된 컴포넌트를 모두 읽어서 연동합니다. 예를 들어 실행할 때에 `config/database.yml` 파일을 통하여 액티브 레코드를 설정합니다. + +**한줄 요약**: 레일스에서 뷰와 관련된 동작을 제외하면 어떤 기능을 사용할 수 있을까요? 기능 대부분을 사용할 수 있습니다. + +기본 설정 +----------------------- + +레일스 애플리케이션을 API 서버로 구축하고 싶다면, 기능을 제한한 레일스 하위 셋을 사용하여 필요한 기능을 +추가하는 것이 좋을 겁니다. + +### 애플리케이션을 새로 생성하기 + +API 레일스 애플리케이션을 생성하려면 다음의 명령을 사용합니다. + +```bash +$ rails new my_api --api +``` + +이 명령은 다음 3개의 동작을 실행합니다. + +- 사용하는 미들웨어를 기존보다 적게끔 설정합니다. 특히 브라우저용 애플리케이션에서 유용한 미들웨어(쿠키 등의 지원)를 완전히 사용할 수 없게 됩니다. +- `ApplicationController`을 `ActionController::Base`가 아닌 `ActionController::API`에서 상속받습니다. 미들웨어와 마찬가지로 액션 컨트롤러 모듈에서 브라우저용 애플리케이션에서만 사용되는 부분을 모두 제외합니다. +- 제너레이터가 뷰, 헬퍼, 어셋을 생성하지 않도록 합니다. + +### 기존의 애플리케이션을 변경하기 + +기존의 애플리케이션을 API 전용으로 만들려면 다음 순서를 따라주세요. + +`config/application.rb`의 `Application` 클래스에 다음을 추가합니다. + +```ruby +config.api_only = true +``` + +`config/environments/development.rb`에서 `config.debug_exception_response_format`을 통해 +개발 모드에서 에러가 발생할 경우에 응답에서 사용할 형식을 지정하세요. + +`:default`는 HTML 페이지로 디버깅 정보를 제공합니다. + +```ruby +config.debug_exception_response_format = :default +``` + +`:api`는 응답 형식을 유지한 채로 디버깅 정보를 제공합니다. + +```ruby +config.debug_exception_response_format = :api +``` + +`config.api_only`를 true로 설정하면 `config.debug_exception_response_format`의 +기본값이 `:api`로 설정됩니다. + +마지막으로 `app/controllers/application_controller.rb`를, + +```ruby +class ApplicationController < ActionController::Base +end +``` + +다음과 같이 변경합니다. + +```ruby +class ApplicationController < ActionController::API +end +``` + +미들웨어 선택하기 +-------------------- + +API 애플리케이션에서는 기본으로 다음의 미들웨어를 사용합니다. + +- `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` +- `ActiveRecord::Migration::CheckPending` +- `Rack::Head` +- `Rack::ConditionalGet` +- `Rack::ETag` + +자세한 설명은 Rack 가이드의 [내부 미들웨어](rails_on_rack.html#미들웨어-스택의-내용)에서 확인하세요. + +미들웨어는 액티브 레코드 등의 플러그인에 의해서 추가되는 경우도 있습니다. 일반적으로 구축할 애플리케이션의 +종류와 미들웨어는 관련이 없습니다만, API 전용 레일스 애플리케이션에서는 의미가 있습니다. + +애플리케이션의 모든 미들웨어를 확인하려면 다음 명령을 실행하세요. + +```bash +$ rails middleware +``` + +### 캐시 미들웨어를 사용하기 + +레일스는 애플리케이션의 설정에 따라 캐시 저장소(기본값은 memcache)를 제공하는 미들웨어를 추가합니다. +다시 말해, 레일스에 포함된 HTTP 캐시는 이 캐시 저장소에 의존합니다. + +예를 들자면, 다음과 같이 `stale?` 메소드를 호출한다고 가정합시다. + +```ruby +def show + @post = Post.find(params[:id]) + + if stale?(last_modified: @post.updated_at) + render json: @post + end +end +``` + +`stale?` 호출은 `@post.updated_at`과 요청에 있는 `If-Modified-Since` 헤더를 비교합니다. 헤더가 마지막 변경 시점보다 새로운 경우 "304 Not Modified"를 반환하거나 `Last-Modified` 헤더를 포함하여 응답을 랜더링합니다. + +일반적으로 이 동작은 클라이언트마다 이루어집니다만, 캐시 미들웨어가 있다면 클라이언트 간에 이 캐시를 +공유할 수도 있습니다. 클라이언트 캐시 공유는 `stale?` 호출 시점에 지정할 수 있습니다. + +```ruby +def show + @post = Post.find(params[:id]) + + if stale?(last_modified: @post.updated_at, public: true) + render json: @post + end +end +``` + +캐시 미들웨어는 URL에 대응하는 `Last-Modified` 값을 레일스 캐시에 저장하고 이후 같은 URL 요청을 +수신할 경우 `If-Modified-Since` 헤더를 추가합니다. + +이는 HTTP를 사용하는 페이지 캐싱이라고 생각할 수도 있을 겁니다. + +### Rack::Sendfile 사용하기 + +레일스 컨트롤러에서 `send_file` 메소드가 실행되면 `X-Sendfile` 헤더가 추가됩니다. +`Rack::Sendfile`은 실제 파일 전송을 책임집니다. + +빠른 파일 전송(accelerated file sending)을 지원하는 프론트엔드 서버는 `Rack::Sendfile` +대신에 실제 파일을 전송합니다. + +프론트엔드 서버에서 파일 전송에 사용하는 헤더의 이름은 해당하는 환경 설정 파일의 +`config.action_dispatch.x_sendfile_header`에서 지정할 수 있습니다. + +[Rack::Sendfile 문서](http://rubydoc.info/github/rack/rack/master/Rack/Sendfile)에서 +인기있는 프론트엔드와 함께 `Rack::Sendfile`을 사용하는 방법을 확인하세요. + +빠른 파일 전송을 사용하려면 헤더에 다음과 같은 값을 설정하세요. + +```ruby +# Apache, lighttpd +config.action_dispatch.x_sendfile_header = "X-Sendfile" + +# Nginx +config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" +``` + +이 옵션을 사용하려면 `Rack::Sendfile` 문서를 따라서 서버를 설정해주세요. + +### ActionDispatch::Request 사용하기 + +`ActionDispatch::Request#params`는 클라이언트로부터 매개변수를 JSON 형식으로 받아 컨트롤러의 +`params`로 접근할 수 있게 해줍니다. + +이 기능을 사용하려면 JSON으로 인코딩된 매개변수를 클라이언트에서 보내고, 이 때 `Content-Type`가 +`application/json`이어야 합니다. + +jQuery 예제는 다음과 같습니다. + +```javascript +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`으로 다음 인자를 받습니다. + +```ruby +{ :person => { :firstName => "Yehuda", :lastName => "Katz" } } +``` + +### 그 이외의 미들웨어 + +레일스에서는 이외에도 API 애플리케이션을 위한 여러 미들웨어를 사용할 수 있습니다. 특히 브라우저가 +API 클라이언트가 되는 경우에 다음의 미들웨어들이 유용합니다. + +- `Rack::MethodOverride` +- `ActionDispatch::Cookies` +- `ActionDispatch::Flash` +- 세션 관리용 + * `ActionDispatch::Session::CacheStore` + * `ActionDispatch::Session::CookieStore` + * `ActionDispatch::Session::MemCacheStore` + +이 미들웨어들은 다음과 같이 추가할 수 있습니다. + +```ruby +config.middleware.use Rack::MethodOverride +``` + +### 미들웨어 제거하기 + +API 전용 미들웨어에 포함하고 싶지 않은 미들웨어는 다음과 같이 삭제할 수 있습니다. + +```ruby +config.middleware.delete ::Rack::Sendfile +``` + +이 미들웨어를 삭제하면 액션 컨트롤러의 일부 기능을 사용할 수 없게 되므로 조심하세요. + +컨트롤러에서 사용할 모듈 선택하기 +--------------------------- + +API 애플리케이션(`ActionController::API`를 사용)에는 다음과 같은 컨트롤러 모듈이 포함됩니다. + +- `ActionController::UrlFor`: `url_for` 등의 헬퍼 제공 +- `ActionController::Redirecting`: `redirect_to` 제공 +- `AbstractController::Rendering`와 `ActionController::ApiRendering`: 기본적인 랜더링을 제공 +- `ActionController::Renderers::All`: `render :json` 등을 제공 +- `ActionController::ConditionalGet`: `stale?`을 제공 +- `ActionController::BasicImplicitRender`: 명시적인 응답이 없으면 빈 응답을 반환 +- `ActionController::StrongParameters`: 매개변수를 위한 화이트리스트를 제공(액티브 모델의 대량 할당과 함께 동작) +- `ActionController::ForceSSL`: `force_ssl`을 제공 +- `ActionController::DataStreaming`: `send_file`이나 `send_data`를 제공 +- `AbstractController::Callbacks`: `before_action` 등의 헬퍼를 제공 +- `ActionController::Rescue`: `rescue_from`을 제공 +- `ActionController::Instrumentation`: 액션 컨트롤러에서 정의하는 계측 훅을 제공([계측 가이드](active_support_instrumentation.html#action-controller)를 참조) +- `ActionController::ParamsWrapper`: 매개변수 해시를 감싸서 중첩된 해시로 만듦. 이를 통해서 POST 요청을 전송하는 경우에도 최상위 요소를 지정하지 않도록 해줌 + +다른 플러그인을 통해 모듈이 추가되는 경우도 있습니다. `ActionController::API`의 모든 모듈 목록은 +다음 명령으로 확인할 수 있습니다. + +```bash +$ bin/rails c +>> ActionController::API.ancestors - ActionController::Metal.ancestors +=> [ActionController::API, + ActiveRecord::Railties::ControllerRuntime, + ActionDispatch::Routing::RouteSet::MountedHelpers, + ActionController::ParamsWrapper, + ... , + AbstractController::Rendering, + ActionView::ViewPaths] +``` + +### 그 외의 모듈 추가하기 + +액션 컨트롤러의 어떤 모듈도 자신이 의존하는 모듈을 파악하고 있으므로 자유롭게 컨트롤러에 모듈을 추가할 수 있습니다. + +자주 사용되는 것은 다음과 같습니다. + +- `AbstractController::Translation`: 지역화용 `l`과 번역용 `t` 메소드를 제공 +- `ActionController::HttpAuthentication::Basic`(그리고 `Digest`, `Token`): HTTP의 기본 인증, 다이제스트 인증, 토큰 인증을 제공 +- `ActionView::Layouts`: 레이아웃을 제공 +- `ActionController::MimeResponds`: `respond_to`을 제공 +- `ActionController::Cookies`: 서명과 암호화를 포함한 `cookies`를 제공. 쿠키 미들웨어가 필요. + +모듈은 `ApplicationController`에 추가하는 것이 가장 좋습니다만, 각각의 컨트롤러에 추가해도 괜찮습니다.