カスタムREST APIを作成
まずは、REST APIを作成します。
REST API自体標準機能が備わっていいますが、今回は引数の検証がしたいので自作で作ります。
REST APIを作る場合、@RestResourceアノテーションと対応するHTTPメソッド用のアノテーションを使用します。
今回はPOSTで検証したいので、ソースコードはこのようになります。
HogeApi.cls
@RestResource(urlMapping='/Hoge/*') global with sharing class HogeApi { @HttpPost global static String doPost(String name, Integer count, Boolean isHello) { String helloStr = ''; String greet = isHello ? 'Hello' : 'Goodbye'; for(Integer i = 0; i < count; i++){ helloStr += greet + ' ' +name + '!'; } return helloStr; } }
ちょっとだけ解説すると、@RestResourceアノテーションでカスタムのREST APIを作るよっていう宣言をします。
urlMappingで指定されたものがAPI URLになります。
urlMappingはhttps://instance.salesforce.com/services/apexrest以降を指定するため、
上記ソースでのAPI URLはhttps://instance.salesforce.com/services/apexrest/Hogeになります。
あとはHttpメソッドに対応するメソッドをクラス内に用意します。
今回はPOSTだけですが、GETを使用したければ、@HttpGetアノテーションをつけてメソッドを定義、PUTやDELETEも同じように使用します。
JSON形式での引数指定
早速作ったAPIでRESTを確認してみましょう。
今回はお手軽なWorkbenchを使用します。
utirityのREST ExplorerからRequest HeadersとRequest Bodyをこのようにします。
Request Headers
Accept:application/xml
Request Body
“name”:”hoge”,
“count”:2,
“isHello”:true
}
Executeで実行すると結果はこのように。
Raw Response
HTTP/1.1 200 OK Date: Sat, 27 Oct 2018 06:34:03 GMT Strict-Transport-Security: max-age=31536000; includeSubDomains X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Content-Security-Policy: upgrade-insecure-requests X-Robots-Tag: none Cache-Control: no-cache,must-revalidate,max-age=0,no-store,private Set-Cookie: BrowserId=6fZOKEZFRviCi6PQewAasA;Path=/;Domain=.salesforce.com;Expires=Wed, 26-Dec-2018 06:34:03 GMT;Max-Age=5184000 Expires: Thu, 01 Jan 1970 00:00:00 GMT Content-Type: application/xml;charset=UTF-8 Transfer-Encoding: chunked
<?xml version=”1.0″ encoding=”UTF-8″?> <response> Hello hoge!Hello hoge!</response>
この通り、成功しています。
ここでのポイントは、引数に文字列、数値、Boolean型をそれぞれ使用していますが、JSONで指定する時のダブルクォートの有無。
数値、Boolean型にはダブルクォートはつきませんので注意しましょう。
また、JSONを以下のように順番を変えても結果は同じでした。
“count”:2,
“isHello”:true,
“name”:”hoge”
}
どうやら、名前がマッチしていれば順番は関係ないようです。
今後は大文字、小文字を変えてみました。
“count”:2,
“ishello“:true,
“name”:”hoge”
}
Raw Response
HTTP/1.1 400 Bad Request Date: Sat, 27 Oct 2018 06:48:14 GMT Strict-Transport-Security: max-age=31536000; includeSubDomains X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Content-Security-Policy: upgrade-insecure-requests X-Robots-Tag: none Cache-Control: no-cache,must-revalidate,max-age=0,no-store,private Set-Cookie: BrowserId=XiOKfTMaQnaOnNw3qcdCgA;Path=/;Domain=.salesforce.com;Expires=Wed, 26-Dec-2018 06:48:14 GMT;Max-Age=5184000 Expires: Thu, 01 Jan 1970 00:00:00 GMT Content-Type: application/xml;charset=UTF-8 Transfer-Encoding: chunked
<?xml version=”1.0″ encoding=”UTF-8″?> <Errors> <Error> <errorCode>JSON_PARSER_ERROR</errorCode> <message>Unexpected parameter encountered during deserialization: ishello at [line:3, column:19]</message> </Error> </Errors>
はい、エラーです。
どうやら大文字小文字は区別するみたいですね。
XML形式での引数指定
次はXML形式で引数を指定してみます。
Request HeadersとRequest Bodyはこのように入力します
Request Headers
Accept:application/xml
Request Body
<name>Hoge</name>
<count>2</count>
<isHello>true</isHello>
</request>
そして結果はこの通り。
Raw Response
HTTP/1.1 200 OK Date: Sat, 27 Oct 2018 07:15:50 GMT Strict-Transport-Security: max-age=31536000; includeSubDomains X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Content-Security-Policy: upgrade-insecure-requests X-Robots-Tag: none Cache-Control: no-cache,must-revalidate,max-age=0,no-store,private Set-Cookie: BrowserId=qZqjJ4UES8Cd8_FRUWCokQ;Path=/;Domain=.salesforce.com;Expires=Wed, 26-Dec-2018 07:15:50 GMT;Max-Age=5184000 Expires: Thu, 01 Jan 1970 00:00:00 GMT Content-Type: application/xml;charset=UTF-8 Transfer-Encoding: chunked
<?xml version=”1.0″ encoding=”UTF-8″?> <response> Hello hoge!Hello hoge!</response>
同じ引数なので同じ結果になりますが、こちらも問題なく動いています。
こちらもJSON形式と同様、順番の入れ替えはOK、大文字小文字は区別します。
こちらは、XML形式なので、ダブルクォートでくくる必要ななく、文字列型であっても、数値型であっても、Boolean型であっても、タグの中に値を記載すればOKです。
ちょっと複雑にしてみる
今後はAPIクラスをちょっと変更して、引数をクラスにします。
HogeApi.cls
@RestResource(urlMapping='/Hoge/*') global with sharing class HogeApi { @HttpPost global static String doPost(HogeHello hoge) { String helloStr = ''; String greet =hoge.isHello ? 'Hello' : 'Goodbye'; for(Integer i = 0; i < hoge.count; i++){ helloStr += greet + ' ' +hoge.name + '!'; } return helloStr; } global class HogeHello{ global String name; global Integer count; global Boolean isHello; } }
この場合の引数指定でも、JSON、XMLともに階層化してあげればOKです。
JSON形式
“hoge”:{
“name”:”hoge”,
“count”:2,
“isHello”:true
}
}
XML形式
<hoge>
<name>Hoge</name>
<count>2</count>
<isHello>true</isHello>
</hoge>
</request>
まとめ
- 大文字・小文字は区別する
- JSON、XMLとも順番は関係ない
- JSON形式では、文字列はダブルクォートでくくり、数値やBooleanはくくらない
- XML形式では、どのデータ型であってもダブルクォートでくくる必要ななく、タグの中に値を記載する
コメント