トップへ(mam-mam.net/)

REST通信してレスポンスのJSONをデコードする ~Delphiソースコード集

検索:

REST通信してレスポンスのJSONをデコードする ~Delphiソースコード集

zipcloud様(https://zipcloud.ibsnet.co.jp/doc/api)の郵便番号検索APIを使わせていただいてREST通信を行い、レスポンスのJSONテキストを以下3つの方法でデコードします。

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をフォームにドラッグドロップします。

Delphi IDE 新規プロジェクト作成とコンポーネントの配置

ソースコード

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
    msg: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に表示されます。

Delphi IDE 新規プロジェクト作成とコンポーネントの配置

注意点

TJsonSerializer、TJsonTextReader、TJsonObjectのどれを使うか悩ましいところです。
サービス業者によっては示されているJSON構造と違う構造(例えばレスポンスが配列で届くと記載されているのにデータが1個の場合は配列で届かない)のJSONテキストが届く場合もあり、 この場合はTJsonSerializerが使えなくてTJsonObjectを使って配列かどうか確認して処理を分岐する必要があります。
ひどいサービス業者になると、パラメータによってはJSONの構文が間違って届く場合もあり、レスポンスのJSONテキストを正規表現等を使って書き換えてからJSONデコードを行った事もあります。
データが配列で届くと記載されているのに、検索結果のデータがない場合にはステータスコードとメッセージのみしか届かないパターンもありました。
レスポンスのJSONテキストのデコードはパターンによって要注意です。