지난 주말 Slugger - 스프링노트 블로그 프론트엔드에 핑백을 구현했다.

 

 

핑백은 가장 간단한 형태의 XML-RPC 서비스다. 내 서버에 있는 글 A에서 너희 서버에 있는 글 B를 링크(인용)했어. 참고해~ 라고 알려주자는 취지며, 이글루스, 워드프레스등의 블로깅 툴에서 주로 지원하고 있다. 

 

지금부터 슬러거에서 핑백을 구현했던 과정을 되짚어보며, 레일스 프로젝트에서 XML-RPC 서버를 구현하는 방법을 살펴보도록 하자.

 

1.2.x 방식

레일스의 구성 요소 중 하나인 액션 웹 서비스(Action Web Service)를 이용하면 웹 서비스를 쉽게 구현할 수 있다. 지저분한 부분(주로 dispatcher의 임무)을 프레임워크가 가려준다. README에서 지시하는대로 몇 가지만 구현하면 된다.

 

먼저 인터페이스를 정의한다. app/apis/pingback_api.rb 파일을 아래처럼 만들어준다.

 

  1. class PingbackAPI < ActionWebService::API::Base
        inflect_names false   
        api_method :ping, :expects => [:string, :string], :returns => [:string]
    end

 

그리고 서비스 파일을 구현한다. 이 파일에는 실제 API 구현 코드를 적어준다. 위치는 app/apis/pingback_service.rb 파일다.

 

  1. require 'pingback_api'
  2.  
  3. class PingbackService < ActionWebService::Base
        web_service_api PingbackAPI
       
        def ping(source_uri, target_uri)
            RAILS_DEFAULT_LOGGER.info "ping #{source_uri}, #{target_uri}"
            0
        end
    end

 

마지막으로 컨트롤러를 구현한다. app/controllers/xmlrpc_controller.rb다.

 

  1. require 'pingback_service'

    class XmlrpcController < ApplicationController
        web_service_dispatching_mode :layered
        web_service :pingback, PingbackService.new
    end

 

웹서비스의 디스패칭 모드는 direct, deligated, layered 3가지가 있다. 그 중 위 예제에서 사용한 layered 모드는 한 컨트롤러로 여러 웹 서비스를 제공할 수 있는 방식으로, 대부분의 웹 애플리케이션에서는 layered 모드를 사용하게 될 것이다.

 

그리고 routes.rb에 다음 라우팅을 추가한다.

 

  1. map.connect 'xmlrpc', :controller => 'xmlrpc', :action => 'api'

 

이제 /xmlrpc 주소로 pingback.ping 메서드를 서비스할 수 있다.

 

핑백 클라이언트

이렇게 구현한 서버에 실제 pingback을 날려보자. 루비 표준 라이브러리에 포함된 xmlrpc 라이브러리를 활용하면 어렵지않게 구현할 수 있다. 

 

  1. require 'xmlrpc/client'

    pingback_url = 'http://localhost:3000/xmlrpc'
    source_uri   = 'http://deepblue.springnote.com/'
    target_uri   = 'http://myruby.net/pages/601210'

    server = XMLRPC::Client.new2(URI.parse(pingback_url).to_s)
    p server.call('pingback.ping', source_uri, target_uri)

 

화면에 0(핑백 성공시 결과값)이 출력되면 성공이다!

 

1.2와 2.0 모두에서 사용할 수 있는 방식

레일스 2.0에서는 1.2.x까지 사용하던 액션 웹 서비스가 퇴출되었다. 대신 액티브리소스가 등장했다(참조: 액티브 리소스와 스프링노트 스크린캐스트). XMLRPC보다는 REST 방식을 선호하는 레일스 커뮤니티의 강한 의지를 반영한 것이다. 최근에는 레일스 개발 trunk에서도 액션 웹 서비스가 제거되었다.

 

 

그림_2.png

 

물론, 액션 웹 서비스를 레일스 2.0에서도 계속 사용할 수도 있다. 하지만 필자의 테스트 결과 그리 추천할만한 것이 못된다. 미묘한 문제가 계속 발생했다. 예를 들면 간헐적인 404(디스패칭이 안되는 문제)등이다.

 

그럼 기존 XMLRPC 서비스를 제공해야하는 애플리케이션들은 어떻게 해야하나? 다행히 XMLRPC 서버 구현 자체는 어렵지 않다. 그리고 xmlrpc 라이브러의 지원도 충분하다. 액션 웹 서비스 없이 구현해보니, 저 프레임워크가 왜 필요했었지? 싶기도 하다. 집 나간 자식(?)은 잊어버리자.

 

먼저 routes 파일에 XMLRPC 엔트리포인트를 정의한다. 1.2 방식과 동일하게 /xmlrpc를 사용하도록 하자.

 

  1.   map.connect 'xmlrpc', :controller => 'xmlrpc', :action => 'api',  :conditions => {:method => :post}

 

차이점은 이 URL을 POST 메서드로 제한했다는 점이다.

 

이제 XmlrpcController#api 메서드를 구현해보자.

 

  1. require "xmlrpc/parser"
    require "xmlrpc/create"
    require "xmlrpc/config"
    require "xmlrpc/utils"         # ParserWriterChooseMixin

    class XmlrpcController < ApplicationController
      session :off
     
      include XMLRPC::ParserWriterChooseMixin
      include XMLRPC::ParseContentType

      def api
        name, data = parser.parseMethodCall(request.raw_post)
        name.gsub!(/\./, '_')
       
        ret = send(name.to_sym, *data)
        xml = create.methodResponse(true, *ret)
        render :text => xml, :content_type => 'text/xml; charset=utf-8'
      end
  2. end

 

XMLRPC 라이브러리의 parser를 이용해 요청 메시지를 분석해서 메서드 이름에 해당하는 메서드를 호출한다. 이 때 '.'는 '_'로 바꿔준다. 예를 들어 pingback.ping 이라면 pingback_ping 메서드를 호출할 것이다. 그리고 그 결과를 받아서 응답 메시지를 만든다(역시 XMLRPC 라이브러리를 활용해서). 어렵지 않게 간단한 XMLRPC 프레임워크가 생겼다. 이제 서비스를 구현만 하면 된다. 아래는 실제 슬러거의 pingback 구현체다.

 

  1.   def pingback_ping(source_uri, target_uri)
        RAILS_DEFAULT_LOGGER.info "ping #{source_uri}, #{target_uri}"
       
        match = target_uri.scan(/\/pages\/(\d+)/)
       
        page_id = match[0].to_s.to_i
        return 0x0020 if page_id <= 0 || !Page.blog_post?(page_id)
       
        page = Page.find(page_id)
        return 0x0020 unless page
       
        Comment.create_pingback page, source_uri
        0
      end

 

지금까지 pingback을 지원하는 간단한 XMLRPC 서비스를 구현해봤다. REST 방식이라면 /pages/:id/ping 리소스를 하나 만들면(POST)될텐데... 개인적으로는 후자가 여러면에서 더 쉬워보인다.  그래도 레거시(이렇게 표현해도 될지 모르겠지만) 애플리케이션들과의 통신을 위해서라면 XMLRPC도 필요할 것이다. 뭐~ XMLRPC든 REST든 API를 제공하는 서비스가 많아졌으면 좋겠다.

 

 

7 Responses to “레일스에서 XML-RPC 서버 구현하기(핑백 구현 예제)”

  1. deepblue Says:
    오호 이아스님의 핑백!
  2. deepblue Says:
    이 글은 ias님의 베타테스팅으로 검증되었습니다. ^^
  3. deepblue Says:
    그리고 스프링북에도 핑백이 적용되었군요!
  4. 꼬루미 Says:
    와 - 슬러거 최신판 빨리 설치하고 싶어요. -0-' 사용자키 어디서 받아요? URL 알려주세요. -_-+
  5. deepblue Says:
    꼬루미// 에고 답변 드린 줄 알았는데 깜빡했어요.. 지금 메일 드렸어요 ^^
  6. deepblue Says:
    와 핑백이다 ㅠㅠ
  7. iron Says:
    좋은 참고가 되었습니다. 혹시 모르니 send 전에 if self.protected_methods(false).include?(name) 정도 넣어주는 것도 좋을 것 같아요. <br/>

Leave a Reply

Website

Email