メッセージ テンプレート

このトピックでは、API プロキシでメッセージ テンプレートを使用する方法の説明と、関数リファレンスを提供します。

メッセージ テンプレートとは

メッセージ テンプレートを使用すると、特定のポリシーと TargetEndpoint 要素で変数文字列置換を行うことができます。この機能に対応している場合は、プロキシの実行時に文字列データを動的に代入できます。

メッセージ テンプレートには、フロー変数参照とリテラル テキストの任意の組み合わせを含めることができます。フロー変数名は中かっこで囲む必要があり、中かっこで囲まれていないテキストはすべてリテラル テキストとして出力されます。

メッセージ テンプレートを使用できる状況もご覧ください。

たとえば、Assign Message ポリシーでは、<Payload> 要素内でメッセージ テンプレートを以下のように使用できます。

<AssignMessage name="set-dynamic-content">
      <AssignTo createNew="false" type="response"></AssignTo>
      <Set>
        <Payload contentType="application/json">
          {"name":"Alert", "message":"You entered an invalid username: {user.name}"}
        </Payload>
      </Set>
      <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
    </AssignMessage>

上の例では、フロー変数 user.name (中かっこ内)の値が評価され、ランタイム時にペイロード文字列に置換されます。このため、たとえば user.name=jdoe であるとすると、ペイロードで生成されるメッセージ出力は You entered an invalid username: jdoe となります。変数を解決できない場合は、空の文字列が出力されます。

割り当て量を超えた場合は、呼び出し元に意味のあるメッセージを返すことをおすすめします。一般にこのパターンは「障害ルール」とともに使用され、呼び出し元に割り当て違反に関する情報を提供することを目的としています。次の AssignMessage ポリシーでは、メッセージ テンプレートを使用して、割り当て情報のデータが複数の XML 要素に動的に代入されます。

<AssignMessage name='AM-QuotaViolationMessage'>
      <Description>message for quota exceeded</Description>
      <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
      <Set>
        <Headers>
          <Header name='X-Quota-Reset'>{ratelimit.Quota-1.expiry.time}</Header>
          <Header name='X-Quota-Allowed'>{ratelimit.Quota-1.allowed.count}</Header>
          <Header name='X-Quota-Available'>{ratelimit.Quota-1.available.count}</Header>
        </Headers>
        <Payload contentType='application/json'>{
      "error" : {
        "message" : "you have exceeded your quota",
        "clientId" : "{request.queryparam.apikey}"
      }
    }
        </Payload>
        <StatusCode>429</StatusCode>
        <ReasonPhrase>Quota Exceeded</ReasonPhrase>
      </Set>
    </AssignMessage>

AssignMessage ポリシーでは、<Set> 要素内の以下の要素でメッセージ テンプレートの使用がサポートされます。

  • Header
  • QueryParam
  • FormParam
  • PayLoad
  • Version
  • Verb
  • Path
  • StatusCode
  • ReasonPhrase

繰返しになりますが、メッセージ テンプレート内のフロー変数は、中かっこで囲む必要があります

このポリシーが実行されると、以下のことが起こります。

  • Header 要素は指定されたフロー変数の値を受け取ります。
  • Payload にリテラル テキストと変数が入り混じって格納されます(client_id は動的に代入されます)。
  • StatusCode と ReasonPhrase には、リテラル テキストのみが格納されますが、これらの要素では必要に応じてメッセージ テンプレートの使用がサポートされます。

プロキシの TargetEndpoint 定義で、<SSLInfo> の子要素ではメッセージ テンプレートの使用がサポートされます。ポリシーで使用したものと同じパターンに従って、中かっこのフロー変数がプロキシの実行時に置換されます。

<TargetEndpoint name="default">
      …
      <HTTPTargetConnection>
        <SSLInfo>
            <Enabled>{myvars.ssl.enabled}</Enabled>
            <ClientAuthEnabled>{myvars.ssl.client.auth.enabled}</ClientAuthEnabled>
            <KeyStore>{myvars.ssl.keystore}</KeyStore>
            <KeyAlias>{myvars.ssl.keyAlias}</KeyAlias>
            <TrustStore>{myvars.ssl.trustStore}</TrustStore>
        </SSLInfo>

      </HTTPTargetConnection>
      …
    </TargetEndpoint>

メッセージ テンプレートを使用できる状況

メッセージ テンプレートは、いくつかのポリシーと、TargetEndpoint 構成で使用される一部の要素でサポートされます。

メッセージ テンプレートを受け入れるポリシー

ポリシー メッセージ テンプレートをサポートする要素と子要素
AccessControl ポリシー <SourceAddress>mask 属性と IP アドレス用)。
AssignMessage ポリシー <Set> 子要素: Payload、ContentType、Verb、Version、Path、StatusCode、ReasonPhrase、Headers、QueryParams、FormParams

<Add> 子要素: Headers、QueryParams、FormParams

<AssignVariable> 子要素: <Template>

ExtensionCallout ポリシー <Input>
ExtractVariables ポリシー <JsonPath>
GenerateJWS ポリシー
VerifyJWS ポリシー
<Payload>GenerateJWS ポリシーのみ)

<AdditionalHeaders><Claim>

* これらの要素は、type=map の場合のみメッセージ テンプレートをサポートします。

GenerateJWT ポリシー
VerifyJWT ポリシー
<AdditionalClaims><Claim>

<AdditionalHeaders><Claim>

* これらの要素は、type=map の場合のみメッセージ テンプレートをサポートします。

LDAP ポリシー <SearchQuery>
MessageLogging ポリシー <Syslog><Message>

<File><Message>

RaiseFault ポリシー <Set> 要素: Payload、ContentType、Verb、Version、Path、StatusCode、ReasonPhrase、Headers、QueryParams、FormParams

<Add> 要素: Headers、QueryParams、FormParams

SAMLAssertion ポリシー <Template>

 * ポリシーの署名が <GenerateSAMLAssertion> の場合のみ

ServiceCallout ポリシー <Set> 要素: Payload、ContentType、Verb、Version、Path、StatusCode、ReasonPhrase、/Headers、QueryParams、FormParams

<Add> 要素: Headers、QueryParams、FormParams

<HTTPTargetConnection>/<URL>: 文字列の最初の部分が http か https である必要があります。

メッセージ テンプレートを受け入れる TargetEndpoint 要素

HTTPTargetConnection 要素 メッセージ テンプレートをサポートする子要素
SSLInfo Enabled、KeyAlias、KeyStore、TrustStore、ClientAuthEnabled、CLRStore
LocalTargetConnection ApiProxy、ProxyEndpoint
Path なし

メッセージ テンプレートの構文

ここでは、メッセージ テンプレートの使用時に適用されるルールについて説明します。

変数を示す中かっこの使用

変数名は中かっこ { } で囲みます。変数が存在しない場合、出力には空の文字列が返されます。ただし、メッセージ テンプレートにデフォルト値(変数が解決されない場合に置換される値)を指定しておくことができます。詳しくは、メッセージ テンプレートのデフォルト値の設定をご覧ください。

メッセージ テンプレートの文字列全体を引用符で囲むことができますが、引用符は省略可能です。たとえば、次の 2 つのメッセージ テンプレートは同じことです。

<Set>
        <Headers>
            <Header name="x-h1">"Hello {user.name}"</Header>
            <Header name="x-h1">Hello {user.name}</Header>
        </Headers>
    </Set>

メッセージ テンプレートのデフォルト値の設定

テンプレート化された変数を解決できない場合、Edge は空の文字列に置換します。ただし、以下のようにしてデフォルト値を指定できます。

 <Header name="x-h1">Test message. id = {request.header.id:Unknown}</Header>
    

上記のサンプルで、変数 request.header.id を解決できない場合、値が Unknown に置換されます。次に例を示します。

Test message. Unknown
    

JSON ペイロードの以前の構文

Cloud リリース 16.08.17 より前の Edge バージョンでは、JSON ペイロード内で中かっこを使用して変数参照を示すことはできませんでした。そのため、次に示すように、variablePrefix 属性と variableSuffix 属性を使用して区切り文字を指定して、これらの変数名を囲む必要がありました。

<Set>
        <Payload contentType="application/json" variablePrefix="@" variableSuffix="#">
            {"name":"foo", "type":"@variable_name#"}
        </Payload>
    </Set>

Apigee では、新しい中かっこの構文の使用をおすすめしますが、以前の構文も機能します。

メッセージ テンプレート関数の使用

Edge には、メッセージ テンプレートで文字列変数のエスケープ、エンコード、ハッシュ、フォーマットに使用できる一連の関数があります。

メッセージ テンプレート関数の詳細については、メッセージ テンプレートの関数リファレンスをご覧ください。

例: toLowerCase()

組み込みの toLowerCase() 関数を使用して、文字列変数を小文字に変換します。

<AssignMessage name="AM-Set-Custom-Response">
        <AssignTo createNew="false" type="response"/>
        <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
        <Set>
            <Headers>
                <Header name="x-h1">Test header: {toLowerCase(foo.bar:FOO)}</Header>
            </Headers>
        </Set>
    </AssignMessage>

foo.bar フロー変数が解決された場合、その文字のすべてが小文字になります。foo.bar が解決されないと、デフォルト値 FOO に置き換えられ、それが小文字に変換されます。次に例を示します。

Test header: foo
    

例: escapeJSON()

興味深い使用例を紹介します。バックエンド アプリが、有効なエスケープ文字を含む JSON レスポンスを返すとします。次に例を示します。

{
          "code": "INVALID",
          "user_message": "Invalid value for \"logonId\" check your input."
    }

次に、このメッセージをカスタム ペイロードでクライアントの呼び出し元に返すとします。通常の方法では、ターゲットのレスポンス ペイロードからメッセージを抽出して、Assign Message を使用してそれをカスタム プロキシ レスポンスに追加します(つまり、クライアントに返信します)。

以下は、user_message 情報を standard.systemMessage という変数に抽出する Extract Variables ポリシーです。

<ExtractVariables name="EV-BackendErrorResponse">
        <DisplayName>EV-BackendErrorResponse</DisplayName>
        <JSONPayload>
            <Variable name="standard.systemMessage">
                <JSONPath>$.user_message</JSONPath>
            </Variable>
        </JSONPayload>
    </ExtractVariables>

そして以下は、抽出された変数をレスポンス ペイロード(プロキシ レスポンス)に追加する、完全に有効な Assign Message ポリシーです。

<AssignMessage name="AM-SetStandardFaultResponse">
        <DisplayName>AM-SetStandardFaultResponse</DisplayName>
        <Set>
            <Payload contentType="application/json">
               {
                  "systemMessage": "{standard.systemMessage}"
               }
            </Payload>
        </Set>
        <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
        <AssignTo createNew="false" transport="http" type="response"/>
    </AssignMessage>


ここで問題が発生します。メッセージ部分を囲むエスケープされた引用符が Extract Variables ポリシーによって削除されてしまいます。このため、クライアントに返されるレスポンスが無効な JSON になっています。これは予期した結果ではありません。

{
        "systemMessage": "Invalid value for "logonId" check your input."
    }

この問題を回避するには、Assign Message ポリシーを変更して、JSON 内の引用符をエスケープするメッセージ テンプレート関数が使用されるようにします。この関数 escapeJSON() は、JSON 表現内に出現する引用符やその他の特殊文字をエスケープします。

<AssignMessage name="AM-SetStandardFaultResponse">
        <DisplayName>AM-SetStandardFaultResponse</DisplayName>
        <Set>
            <Payload contentType="application/json">
               {
                  "systemMessage": "{escapeJSON(standard.systemMessage)}"
               }
            </Payload>
        </Set>
        <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
        <AssignTo createNew="false" transport="http" type="response"/>
    </AssignMessage>


この関数によって埋め込まれた引用符がエスケープされるため、有効な JSON が生成され、予期したとおりの結果が得られます。

{
          "systemMessage": "Invalid value for \"logonId\" check your input.",
    }

メッセージ テンプレートは動的な文字列置換機能であり、特定のポリシー内と TargetEndpoint 定義内で使用できます。メッセージ テンプレートの関数を使用すると、メッセージ テンプレート内でハッシュ、文字列操作、文字のエスケープなどの便利なオペレーションを実行できます。

たとえば、次の AssignMessage ポリシーでは、メッセージ テンプレートで関数 toLowerCase() が使用されています。

<AssignMessage name="AM-Set-Custom-Response">
        <AssignTo createNew="false" type="response"/>
        <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
        <Set>
           <Headers>
             <Header name="x-h1">Test header: {Hello, toLowerCase(user.name)}</Header>
           </Headers>
        </Set>
    </AssignMessage>

このトピックでは、メッセージ テンプレートの関数、その引数、出力について説明します。このトピックは、メッセージ テンプレートとその使用状況について十分な知識があることを前提として作成されています。

ハッシュ関数

ハッシュ値を計算して、そのハッシュの文字列表現を返します。

16 進ハッシュ関数

ハッシュ値を計算して、そのハッシュの文字列表現を 16 進数として返します。

構文

関数 説明
md5Hex(string) 16 進数で表現される MD5 ハッシュを計算します。
sha1Hex(string) 16 進数で表現される SHA1 ハッシュを計算します。
sha256Hex(string) 16 進数で表現される SHA256 ハッシュを計算します。
sha384Hex(string) 16 進数で表現される SHA384 ハッシュを計算します。
sha512Hex(string) 16 進数で表現される SHA512 ハッシュを計算します。

引数

string - ハッシュ関数は、ハッシュ アルゴリズムが計算される単一の文字列引数を取得します。この引数には、リテラル文字列か文字列フロー変数を指定できます。

関数呼び出し:

sha256Hex('abc')
    

結果:

ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
    

関数呼び出し:

var str = 'abc';
    sha256Hex(str)
    

結果:

ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
    

Base64 ハッシュ関数

ハッシュ値を計算し、そのハッシュの文字列表現を Base64 エンコード値として返します。

構文

関数 説明
md5Base64(string) Base64 エンコード値として表現される MD5 ハッシュを計算します。
sha1Base64(string) Base64 エンコード値として表現される SHA1 ハッシュを計算します。
sha256Base64(string) Base64 エンコード値として表現される SHA256 ハッシュを計算します。
sha384Base64(string) Base64 エンコード値として表現される SHA384 ハッシュを計算します。
sha512Base64(string) Base64 エンコード値として表現される SHA512 ハッシュを計算します。

引数

string - ハッシュ関数は、ハッシュ アルゴリズムが計算される単一の文字列引数を取得します。この引数には、リテラル文字列か文字列フロー変数を指定できます。

関数呼び出し:

sha256Base64('abc')
    

結果:

OghSaGiHHx1fTv3y8SKdZYAoGHcqBUpKjNJyGDJ11T215Acw1orz3N2L/NlbwelxZ5R2kuPHuNDb1ZzttKplCg==
    

関数呼び出し:

var str = 'abc';
    sha256Base64(str)
    

結果:

OghSaGiHHx1fTv3y8SKdZYAoGHcqBUpKjNJyGDJ11T215Acw1orz3N2L/NlbwelxZ5R2kuPHuNDb1ZzttKplCg==
    

文字列関数

メッセージ テンプレート内の文字列に対してオペレーションを実行します。

Base64 エンコード関数

Base64 エンコード スキームを使用して文字列をエンコード / デコードします。

構文

関数 説明
encodeBase64(string) Base64 エンコードを使用して文字列をエンコードします。例: encodeBase64(value) で、valueabc が格納されている場合、この関数は文字列 YWJj を返します。
decodeBase64(string) Base64 でエンコードされた文字列をデコードします。例: decodeBase64(value) で、valueaGVsbG8sIHdvcmxk が格納されている場合、この関数は文字列 hello, world を返します。

引数

string - エンコードまたはデコードの対象の文字列。リテラル文字列または文字列フロー変数を使用できます。

<AssignMessage name="AM-Set-Custom-Response">
        <AssignTo createNew="false" type="response"/>
        <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
        <Set>
           <Headers>
             <Header name="x-h1">Hello, {decodeBase64('d29ybGQK')}</Header>
           </Headers>
        </Set>
    </AssignMessage>

大文字と小文字の変換関数

文字列すべてを大文字または小文字に変換します。

構文

関数 説明
toUpperCase(string) 文字列を大文字に変換します。
toLowerCase(string) 文字列を小文字に変換します。
encodeBase64(string) Base64 エンコードを使用して文字列をエンコードします。例: encodeBase64(value) で、valueabc が格納されている場合、この関数は文字列 YWJj を返します。
decodeBase64(string) Base64 でエンコードされた文字列をデコードします。例: decodeBase64(value) when value holds aGVsbG8sIHdvcmxk, the function returns the string hello, world.


引数

string - 変換対象の文字列。リテラル文字列または文字列フロー変数を使用できます。

<AssignMessage name="AM-Set-Custom-Response">
        <AssignTo createNew="false" type="response"/>
        <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
        <Set>
           <Headers>
             <Header name="x-h1">Hello, {toLowerCase(user.name)}</Header>
           </Headers>
        </Set>
    </AssignMessage>

Substring 関数

開始インデックスと終了インデックスの間の文字を、指定された文字列に置き換えます。

構文

substring(str, start_index, end_index)
    

引数

  • str - リテラル文字列または文字列フロー変数。
  • start_index - 文字列の開始インデックス。文字列の置換はここから開始されます。
  • end_index - (省略可)文字列の終了インデックス。指定されていない場合は、開始インデックスから文字列の最後までが置換されます。

以降の例では、次のフロー変数が存在すると想定されています。

変数名
alpha ABCDEFGHIJKLMNOPQRSTUVWXYZ
seven 7


上記の変数を使用した関数呼び出しの結果を以下に示します。

メッセージ テンプレートの表現 結果
{substring(alpha, 22)} WXYZ
hello {substring(alpha, 22)} hello WXYZ
{substring(alpha, -4)} WXYZ
{substring(alpha, -8, -4)} STUV
{substring(alpha, 0, 10)} ABCDEFGHIJ
{substring(alpha, 0, seven)} ABCDEFG

Replace All 関数

文字列に正規表現を適用し、一致する場合は一致したものを置換値に置き換えます。

構文

replaceAll(string, regex, value)
    

引数

  • string - 置換対象のリテラル文字列または文字列フロー変数。
  • regex - 正規表現。
  • value - 文字列内で正規表現と一致したすべての文字列を置き換える値。

以降の例では、次のフロー変数が存在すると想定されています。

変数名
header Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZ-9993
regex1 "^Bearer "
replacement "TOKEN: "

上記の変数を使用した関数呼び出しの結果を以下に示します。

メッセージ テンプレートの表現 結果
{replaceAll(header, "9993", '')} Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZ-
{replaceAll(header, regex1, '')} ABCDEFGHIJKLMNOPQRSTUVWXYZ-9993
{replaceAll(header, regex1, replacement)} TOKEN: ABCDEFGHIJKLMNOPQRSTUVWXYZ-9993

Replace First 関数

文字列内で指定された正規表現と最初に一致したもののみを置き換えます。

構文

replaceFirst(string, regex, value)
    

引数

  • string - 置換対象のリテラル文字列または文字列フロー変数。
  • regex - 正規表現。
  • value - 文字列内で正規表現と一致した文字列を置き換える値。

文字のエスケープとエンコードの関数

文字列内の特殊文字をエスケープまたはエンコードする関数。

構文

関数 説明
escapeJSON(string) 二重引用符をバックスラッシュでエスケープします。
escapeXML(string) 山かっこ、アポストロフィ、二重引用符、アンパサンドをそれぞれの XML エンティティに置き換えます。XML 1.0 ドキュメントに使用します。

escapeXML11(string) escapeXML と同様に機能しますが、XML v1.1 エンティティ専用です。後述の「使用上の注意」をご覧ください。
encodeHTML(string) アポストロフィ、山かっこ、アンパサンドをエンコードします。

引数

string - エスケープ対象の文字列。リテラル文字列または文字列フロー変数を使用できます。

使用上の注意

XML 1.1 では、一部の制御文字を表記できますが、null バイトまたはペアになっていない Unicode サロゲート コードポイントはエスケープ適用後でも表記できません。escapeXML11() 関数では、次の範囲に適合しない文字が削除されます。

[#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
    

escapeXML11() 関数は、次の範囲の文字をエスケープします。

[#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]
    

food というフロー変数があり、値として "bread" & "butter" が格納されているとします。次の関数を使用するとします。

{escapeHTML(food)}
    

結果は次のようになります。

&quot;bread&quot; &amp; &quot;butter&quot;

時間表示形式の関数

時間の文字列表記をローカルタイム ゾーンまたは UTC の形式で返します。

構文

関数 説明
timeFormat(format, str) ローカルタイム ゾーン形式の日付を返します。
timeFormatMS(format, str) ローカルタイム ゾーン形式の日付を返します。
timeFormatUTC(format, str) UTC 形式の日付を返します。
timeFormatUTCMs(format, str) UTC 形式の日付を返します。

引数

  • format - 日付 / 時刻形式の文字列。リテラル文字列または文字列変数を使用できます。
  • str - 時刻値を含む文字列または文字列フロー変数。この値は、エポック時間(秒)か、timeFormatMs の場合はエポック時間(ミリ秒)です。

以下の値を想定してみます。ローカルタイム ゾーンは Pacific とします。

  • epoch_time_ms = 1494390266000
  • epoch_time = 1494390266
  • fmt1 = yyyy-MM-dd
  • fmt2 = yyyy-MM-dd HH-mm-ss
  • fmt3 = yyyyMMddHHmmss

各関数から次の結果が返されます。

    関数 出力
    timeFormatMs(fmt1,epoch_time_ms) 2017-05-09
    timeFormat(fmt1,epoch_time) 2017-05-09
    timeFormat(fmt2,epoch_time) 2017-05-09 21:24:26
    timeFormat(fmt3,epoch_time) 20170509212426
    timeFormatUTC(fmt1,epoch_time) 2017-05-10
    timeFormatUTC(fmt2,epoch_time) 2017-05-10 04:24:26
    timeFormatUTC(fmt3,epoch_time) 20170510042426

    その他の関数

    Create UUID 関数

    UUID を生成して返します。

    構文

    createUuid()
        

    引数

    なし

    {createUuid()}

    結果のサンプル

    ec3ca9be-d1e1-4ef4-aee4-4a58f3130db8
        

    Random Long Generator 関数

    ランダムの長整数を返します。

    構文

    randomLong(args)
        

    引数

    • 引数を指定しない場合、この関数は Java SecureRandom クラスによって計算されたランダムな長整数を返します。
    • 引数を 1 つ指定する場合は、計算の最小値として処理されます。
    • 引数を 2 つ指定する場合は、2 つ目の引数が計算の最大値として処理されます。

    {random()}
        

    次のような結果が返されます。

    5211338197474042880
        

    正規表現テキスト ジェネレータ

    指定の正規表現と一致するテキスト文字列が返されます。

    構文

    xeger(regex)
        

    引数

    regex - 正規表現。

    この例では、ゼロが含まれない 7 桁の文字列が生成されます。

    xeger( '[1-9]{7}' )
        

    例の結果

    9857253
        

    JSON Path 関数

    JSON 変数に JSON Path 表現を適用します。

    構文

    jsonPath(json-path, json-var)
        

    引数

    json-path - JSON Path 表現。

    json-var - フロー変数または JSON を含む文字列。

    以下のメッセージ テンプレートがあるとします。

    The address is {jsonPath($.results[?(@.name == 'Mae West')].address.line1, the_json_variable)}
        

    この the_json_variable に以下が含まれるとします。

    {
              "results" : [
                {
                  "address" : {
                    "line1" : "18250 142ND AV NE",
                    "city" : "Woodinville",
                    "state" : "Washington",
                    "zip" : "98072"
                  },
                  "name" : "Fred Meyer"
                },
                {
                  "address" : {
                    "line1" : "1060 West Addison Street",
                    "city" : "Chicago",
                    "state" : "Illinois",
                    "zip" : "60613"
                  },
                  "name" : "Mae West"
                }
              ]
            } 

    この場合、関数の結果は次のようになります。

    The address is 1060 West Addison Street