REST通信してレスポンスのJSONをデコードする ~Delphiソースコード集
zipcloud様(https://zipcloud.ibsnet.co.jp/doc/api)の郵便番号検索APIを使わせていただいてREST通信を行い、レスポンスのJSONテキストを以下3つの方法でデコードします。
- TJsonSerializerを使ってJsonデコード(System.JSON.Serializers)
- TJsonTextReaderを使ってJsonデコード(System.JSON.Readers, System.JSON.Builders)
- TJsonObjectを使ってJsonデコード(System.JSON)
zipcloud様の郵便番号検索API
https://zipcloud.ibsnet.co.jp/doc/api
を見ればわかるのですが、
- リクエストURL
- https://zipcloud.ibsnet.co.jp/api/search
- パラメータ
- zipcode=7桁の郵便番号
- メソッド
- GET
(例)https://zipcloud.ibsnet.co.jp/api/search?zipcode=0790177 で以下のレスポンス(JSONテキスト)が届きます。
{ "message":null, "results":[ { "address1":"北海道", "address2":"美唄市", "address2":"上美唄町協和", "kana1":"ホッカイドウ", "kana2":"ビバイシ", "kana3":"カミビバイチョウキョウワ", "prefcode":"1", "zipcode":"0790177" }, { 配列なので複数ヒットの場合は上記と同じ構造 }, ・・・配列の数だけ続く ], status: 200 }
画面設計
Delphiを起動したら[ファイル]⇒[新規作成]⇒[Windows VCL アプリケーション]をクリックして新規プロジェクトを作成します。
TRESTClient、TRESTRequest、TRESTResponseをフォームにドラッグドロップします。
TButtonとTEditとTMemoをフォームにドラッグドロップします。
ソースコード
Button1をダブルクリックしてソースコードを入力します。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IPPeerClient, Vcl.StdCtrls,
Data.Bind.Components, Data.Bind.ObjectScope, REST.Client, REST.Types,;
type
TForm1 = class(TForm)
RESTClient1: TRESTClient;
RESTRequest1: TRESTRequest;
RESTResponse1: TRESTResponse;
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses System.JSON.Serializers,
System.JSON.Readers,System.JSON.Builders,
System.JSON;
//■TJsonSerializerを使ってJsonデコードする場合
function DecodeTJsonSerializer(AJson:string):string;
type
TResult=record
zipcode:string;
prefcode:string;
address1:string;
address2:string;
address3:string;
kana1:string;
kana2:string;
kana3:string;
end;
TAddress=record
// messageはDelphiの予約語なので先頭に&を付けて宣言する
&message:string;
results:array of TResult;
status:Integer ;
end;
var res:TAddress;
s:TJsonSerializer;
i:Integer;
begin
s:=TJsonSerializer.Create;
res:=s.Deserialize<TAddress>(AJson);
for i := 0 to Length(res.results)-1 do
begin
result:=result+'住所:'+
res.results[i].address1+
res.results[i].address2+
res.results[i].address3+#13#10;
end;
result:=result+'ステータス:'+IntToStr(res.status)+#13#10;
end;
//■TJsonTextReaderを使ってJsonデコードする場合
function DecodeTJsonTextReader(AJson:string):string;
var sr:TStringReader;
JsonTr:TJsonTextReader;
JsonIt:TJSONIterator;
begin
sr:=TStringReader.Create(AJson);
JsonTr:=TJsonTextReader.Create(sr);
JsonIt:=TJsonIterator.Create(JsonTr);
JsonIt.Next('results');
JsonIt.Recurse;//配列の中に入る
while JsonIt.Next do //配列内でループ
begin
JsonIt.Recurse;//連想配列の中に入る
JsonIt.Next('address1');
result:=result+'住所;'+JsonIt.AsString;
JsonIt.Next('address2');
result:=result+JsonIt.AsString;
JsonIt.Next('address3');
result:=result+JsonIt.AsString+#13#10;
JsonIt.Return;//連想配列から抜ける
end;
JsonIt.Return;//配列から抜ける
JsonIt.Next('status');
result:=result+'ステータス:'+IntToStr(JsonIt.AsInteger)+#13#10;
end;
//■TJsonObjectを使ってJsonデコードする場合
function DecodeTJsonObject(AJson:string):string;
var jv1,jv2,jv3:TJsonValue;
i:Integer;
begin
jv1:=TJsonObject.ParseJSONValue(AJson);
jv2:=jv1.GetValue<TJsonValue>('results');
//"results"が配列かどうかを確認する
if jv2 is TJSONArray then
begin
for i := 0 to TJSONArray(jv2).Count-1 do
begin
jv3:=TJSONArray(jv2).Items[i];
result:=result+'住所:'+jv3.GetValue<string>('address1');
result:=result+jv3.GetValue<string>('address2');
result:=result+jv3.GetValue<string>('address3')+#13#10;
end;
end;
result:=result+'ステータス:'+IntToStr(jv1.GetValue<integer>('status'));
end;
procedure TForm1.Button1Click(Sender: TObject);
var st:String;
begin
//コンポーネントのプロパティ設定
RESTRequest1.Client:=RESTClient1;
RESTRequest1.Response:=RESTResponse1;
Memo1.ScrollBars:=ssBoth;
//URLを分割して入れていますがBaseURLに全部入れても良い
RESTClient1.BaseURL:='https://zipcloud.ibsnet.co.jp/';
RESTRequest1.Resource:='api';
RESTRequest1.ResourceSuffix:='search';
//GETメソッドに設定する
RESTRequest1.Method:=TRestrequestMethod.rmGET;
//REST APIにパラメーターを設定する
RESTRequest1.Params.Clear;
RESTRequest1.Params.AddItem('zipcode',Edit1.Text);//郵便番号設定
//REST API呼び出し
RESTRequest1.Execute;
//レスポンスの受け取り(JSON形式のテキスト)
st:=RESTResponse1.Content;
//テキストのLFをCRLFに変換する
st:=StringReplace(st,#$0A,#$0D#$0A,[rfReplaceAll]);
Memo1.Clear;
//JSON形式テキストをそのまま表示する
Memo1.Lines.Add(st);
Memo1.Lines.Add('');
//TJsonSerializerを使ってJsonデコード
Memo1.Lines.Add('■TJsonSerializerを使ってJsonデコード');
Memo1.Lines.Add(DecodeTJsonSerializer(st));
//TJsonTextReaderを使ってJsonデコード
Memo1.Lines.Add('■TJsonTextReaderを使ってJsonデコード');
Memo1.Lines.Add(DecodeTJsonTextReader(st));
//TJsonObjectを使ってJsonデコード
Memo1.Lines.Add('■TJsonObjectを使ってJsonデコード');
Memo1.Lines.Add(DecodeTJsonObject(st));
end;
end.
実行する
アプリケーションをコンパイルして実行します。
Edit1に「0790177」を入力して、Button1をクリックします。
Rest APIを呼び出して、レスポンスがMemo1に表示されます。
注意点
TJsonSerializer、TJsonTextReader、TJsonObjectのどれを使うか悩ましいところです。
サービス業者によっては示されているJSON構造と違う構造(例えばレスポンスが配列で届くと記載されているのにデータが1個の場合は配列で届かない)のJSONテキストが届く場合もあり、
この場合はTJsonSerializerが使えなくてTJsonObjectを使って配列かどうか確認して処理を分岐する必要があります。
ひどいサービス業者になると、パラメータによってはJSONの構文が間違って届く場合もあり、レスポンスのJSONテキストを正規表現等を使って書き換えてからJSONデコードを行った事もあります。
データが配列で届くと記載されているのに、検索結果のデータがない場合にはステータスコードとメッセージのみしか届かないパターンもありました。
レスポンスのJSONテキストのデコードはパターンによって要注意です。