Skip to content
2012/02/25 / eikiyan

Sitesの機能で公開RESTfulウェブサービスを試してみました(Apex)

Force.com Blogsで公開されてたTipsが気になったので試してみました。
 

Tipsの記事→Quick Tip – Public RESTful Web Services on Force.com Sites
 

ちょうど下記のような要件でサービスを用意できると嬉しい事情があったので、その辺を中心に調べました。

  • 通信は HTTPSでPOSTメソッドを利用
  • リクエストに付加されているBasic認証のヘッダが読める
  • 呼び出し元が決めたXML形式のリクエストボディーが解析できる
  • 呼び出し元が決めたXML形式のレスポンスが返せる

 

呼び出し元の仕様に合わせなければいけないため、OAuthのトークン使った認証とか、SessionID使った認証が出来ず、プライベートなRESTfulウェブサービスでは対応出来ないでいました。

かといって、普通のVisualforceページをSitesに置いて、Apexのコントローラでリクエストを受けようとしたら、Basic認証のヘッダは読めたり、レスポンスには自由なXMLを返せたりしたんですが、リクエストのXMLを読むことが出来ませんでした。(Content-Typeにapplication/xmlが指定されていると、検証した範囲ではどうやっても取れませんでした。)
 

そこにちょうどいいタイミングで、Tipsが公開されたので、試してみたわけです。
結果的には、Authorizationヘッダが見えなかったので、今回の事情には合わなかったんですが・・・、それ以外は問題無さそうでした。
 

API要求数が増えないこと、そのかわりにSitesの要求時間(と、多分転送量も)がカウントされていることは確認できたので、Sitesの制限には気をつける必要があるようです。

また、SSLは必須のようで、HTTPではアクセスできませんでした。(UNSUPPORTED_CLIENTというエラーコードで、HTTPS Requiredというメッセージが返ってきました。)

誰に見られても問題ないようなデータで、大量にアクセスされることがなければ利用できるのかな、と思います。
(あ、IP制限試してないや・・・。)
 

実験に使ったサンプルは続きに。設定方法とかは、最初にリンクを載せたForce.com Blogのほうで確認してください。

 

サンプルのウェブサービスは、リクエスト内のname要素の中身を、そのままgreeting要素に入れて返すだけです。
ところどころのSystem.debugは動作確認用です。
DOMで処理するのも面倒だったので、XMLは文字列として処理してます。
 

サービスクラス

@RestResource(urlMapping='/myservice')
global class MyService {
    @HttpPost
    global static void doPost() {
        RestContext.response.addHeader('Content-Type', 'application/xml');
        String req = RestContext.request.requestBody.toString();
        for (String s : RestContext.request.headers.keySet()) {
            System.debug('Header : ' + s + ' : ' + RestContext.request.headers.get(s));
        }
        System.debug(req);
        String name = 'Anonymous';
        Matcher m = Pattern.compile('<name>(.+)</name>').matcher(req);
        if (m.find()) {
            name = m.group(1);
        }
        String res = '<?xml version="1.0" encoding="UTF-8" ?><greeting>Hello ' + name + '!</greeting>';
        RestContext.response.responseBody = Blob.valueOf(res);
    }
}

 

ついでに、検証に使ったPOSTを送るだけのVisualforceページとコントローラも載せときます。
ページに表示された「test」ボタンをクリックすると、裏でリクエストを投げて、返ってきたレスポンスをそのまんま表示するだけです。
(コールアウトするので、リモートサイト設定が必要です。)
 

コントローラ

public with sharing class SitesRestPost {
    public String response {get; set;}
    public PageReference  testAction() {
        String reqStr = '<?xml version="1.0" encoding="UTF-8"?><user><name>あいうえお</name></user>';
        HttpRequest req = new HttpRequest();
        req.setMethod('POST');
        // URLは内緒
        req.setEndpoint('https:// ---SitesのURL---- /services/apexrest/myservice');
        req.setHeader('Content-Type', 'application/xml');
        req.setHeader('Authorization', 'Basic ' + Encodingutil.base64Encode(Blob.valueOf('testtesttest')));
        req.setBody(reqStr);
        Http h = new Http();
        HttpResponse res = h.send(req);
        response = res.getBody();
        return null;
    }
}

ページ

<apex:page controller="SitesRestPost">
    <apex:form>
        <apex:commandButton action="{!testAction}" value="test"  rerender="resblock" />
    </apex:form>
    <apex:outputPanel layout="block" id="resblock">
      <div>Response:</div>
      <apex:outputText value="{!response}" />
    </apex:outputPanel>
</apex:page>

 

こんなところでしょうか。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。