FileMakerでURLをパースするカスタム関数を作りました
AWSのSDKなどを使わずに、AWSのAPIを利用する際に、リクエストのヘッダーに署名を含める必要があります。
詳細は、以下のリンクを参照して頂きたいです。
AWS API リクエストの署名 - AWS 全般のリファレンス

海外のサンプルファイルを色々と見ましたが、やはり、自分で手を動かして、コードを書かないと理解できないので、ドキュメントを見て実装しました。
手が空いたら、会社のブログで、AWSのAPIを実行する方法については、記事を書きたいと思います…
...
更新履歴(2022–12–27)
会社のブログを更新しました。
FileMaker から S3 や EC2 などの AWS の API を利用する方法 | フルーデンス

...
更新履歴(2023–03–06)
カスタム関数にバグがあったので、修正しました。
...
上記のAWSのドキュメントの通りですが、AWSのAPI をリクエストする際に、hostとかパスとかクエリーが必要になります。
そのためにタイトルの通り、カスタム関数を作りました。
余談ですが…
カスタム関数を公開しましたら Nice!! とコメントを頂きました。
一言だとしても、コメント頂くと意外に嬉しいものですね。
私も、今後は Nice!! など気軽にコメントするように心がけます。
カスタム関数について
ParseUrl ( _url )
試したい方は、以下のURLを参照して、自分のカスタムAppに追加して頂ければと思います。
FileMaker Custom Function: ParseUrl ( _url )

コード
/* --------------------------------------------------------------------------- ParseUrl ( _url ) Description: Parse the URL and return the result as JSON. Note: - If urlIsEmpty is 'false', the URL may have failed to parse. - Please let me know if there is anything I have overlooked. - For the structure of the URL, I referred to the URL below. https://en.wikipedia.org/wiki/URL Example: ParseUrl ( "https://username:[email protected]:80/dir1/file.txt?q1=v1&q2=v2#fragment" ) -> {"fileName":"file.txt","fragment":"fragment","host":"bucketname.s3.ap-northeast-1.amazonaws.com","password":"password","path":"/dir1/file.txt","port":"80","query":"q1=v1&q2=v2","scheme":"https","urlIsEmpty":true,"userName":"username"} ParseUrl ( "https://en.wikipedia.org/wiki/URL" ) -> {"fileName":"","fragment":"","host":"en.wikipedia.org","password":"","path":"/wiki/URL","port":"","query":"","scheme":"https","urlIsEmpty":true,"userName":""} History: 2022-11-24, Teruhiro Komaki <[email protected]> --------------------------------------------------------------------------- */ Let ( [ // _url = "https://username:[email protected]:80/dir1/file.txt?q1=v1&q2=v2#fragment" ; ~url = _url ; ~scheme = GetValue ( Substitute ( ~url ; "://" ; "¶" ) ; 1 ) ; ~url = Substitute ( ~url ; ~scheme & "://" ; "" ) ; ~userinfo = If ( PatternCount ( ~url ; "@" ) ; GetValue ( Substitute ( ~url ; "@" ; "¶" ) ; 1 ) ) ; ~userinfoList = Substitute ( ~userinfo ; ":" ; "¶" ) ; ~userName = GetValue ( ~userinfoList ; 1 ) ; ~password = GetValue ( ~userinfoList ; 2 ) ; ~url = If ( not IsEmpty ( ~userinfo ) ; Substitute ( ~url ; ~userinfo & "@" ; "" ) ; ~url ) ; ~host = GetValue ( Substitute ( ~url ; [ ":" ; "¶" ] ; [ "/" ; "¶" ] ; [ "?" ; "¶" ] ; [ "#" ; "¶" ] ) ; 1 ) ; ~url = Substitute ( ~url ; ~host ; "" ) ; ~port = GetAsNumber ( GetValue ( Substitute ( ~url ; [ "/" ; "¶" ] ; [ "?" ; "¶" ] ; [ "#" ; "¶" ] ) ; 1 ) ) ; ~url = If ( not IsEmpty ( ~port ) ; Substitute ( ~url ; ":" & ~port ; "" ) ; ~url ) ; ~path = GetValue ( Substitute ( ~url ; [ "?" ; "¶" ] ; [ "#" ; "¶" ] ) ; 1 ) ; ~url = If ( not IsEmpty ( ~path ) ; Substitute ( ~url ; ~path ; "" ) ; ~url ) ; ~pathList = Substitute ( ~path ; "/" ; "¶" ) ; ~pathListLast = GetValue ( ~pathList ; ValueCount ( ~pathList ) ) ; ~fileName = If ( GetAsBoolean ( PatternCount ( ~pathListLast ; "." ) ) ; ~pathListLast ; "" ) ; ~fragment = GetValue ( Substitute ( ~url ; [ "#" ; "¶" ] ) ; 2 ) ; ~url = If ( not IsEmpty ( ~fragment ) ; Substitute ( ~url ; "#" & ~fragment ; "" ) ; ~url ) ; ~query = GetValue ( Substitute ( ~url ; [ "?" ; "¶" ] ) ; 2 ) ; ~url = If ( not IsEmpty ( ~query ) ; Substitute ( ~url ; "?" & ~query ; "" ) ; ~url ) ; ~urlIsEmpty = If ( IsEmpty ( ~url ) ; True ; False ) ] ; JSONSetElement ( "" ; [ "scheme" ; ~scheme ; JSONString ] ; [ "userName" ; ~userName ; JSONString ] ; [ "password" ; ~password ; JSONString ] ; [ "host" ; ~host ; JSONString ] ; [ "port" ; ~port ; JSONString ] ; [ "path" ; ~path ; JSONString ] ; [ "fileName" ; ~fileName ; JSONString ] ; [ "fragment" ; ~fragment ; JSONString ] ; [ "query" ; ~query ; JSONString ] ; [ "urlIsEmpty" ; ~urlIsEmpty ; JSONBoolean ] ) ) /*Let*/
コード(2023-03-06)
/* --------------------------------------------------------------------------- ParseUrl ( _url ) Description: Parse the URL and return the result as JSON. Note: - If urlIsEmpty is 'false', the URL may have failed to parse. - Please let me know if there is anything I have overlooked. - For the structure of the URL, I referred to the URL below. https://en.wikipedia.org/wiki/URL Example: ParseUrl ( "https://username:[email protected]:80/dir1/file.txt?q1=v1&q2=v2#fragment" ) -> {"fileName":"file.txt","fragment":"fragment","host":"bucketname.s3.ap-northeast-1.amazonaws.com","password":"password","path":"/dir1/file.txt","port":"80","query":"q1=v1&q2=v2","scheme":"https","urlIsEmpty":true,"userName":"username"} ParseUrl ( "https://en.wikipedia.org/wiki/URL" ) -> {"fileName":"","fragment":"","host":"en.wikipedia.org","password":"","path":"/wiki/URL","port":"","query":"","scheme":"https","urlIsEmpty":true,"userName":""} ParseUrl ( "https://username:[email protected]:80/path/to/file.txt?list-type=2&prefix=s3Prefix/a/b/#fragment" ) -> {"fileName":"file.txt","fragment":"fragment","host":"bucket-demo.s3.us-east-1.amazonaws.com","password":"password","path":"/path/to/file.txt","port":"80","query":"list-type=2&prefix=s3Prefix/a/b/","scheme":"https","urlIsEmpty":true,"userName":"username"} History: 2022-11-24, Teruhiro Komakicreate. 2023-02-24, Teruhiro Komaki It was fixed because it did not consider the case where "/" was included in the query. --------------------------------------------------------------------------- */ Let ( [ // _url = "https://username:[email protected]:80/path/to/file.txt?list-type=2&prefix=s3Prefix/a/b/#fragment" ; ~url = _url ; ~urlLength = Length ( ~url ) ; // scheme ~scheme = GetValue ( Substitute ( ~url ; "://" ; "¶" ) ; 1 ) ; ~schemeLength = Length ( ~scheme & "://" ) ; ~url = Middle ( ~url ; ( ~schemeLength + 1 ) ; ~urlLength ) ; //userInfo ~userinfo = If ( PatternCount ( ~url ; "@" ) ; GetValue ( Substitute ( ~url ; "@" ; "¶" ) ; 1 ) ) ; // username:password@ ~userinfoLength = Length ( ~userinfo & "@" ) ; ~userinfoList = Substitute ( ~userinfo ; ":" ; "¶" ) ; ~userName = GetValue ( ~userinfoList ; 1 ) ; ~password = GetValue ( ~userinfoList ; 2 ) ; ~url = If ( not IsEmpty ( ~userinfo ) ; Middle ( ~url ; ( ~userinfoLength + 1 ) ; ~urlLength ) ; ~url ) ; // host ~host = GetValue ( Substitute ( ~url ; [ ":" ; "¶" ] ; [ "/" ; "¶" ] ; [ "?" ; "¶" ] ; [ "#" ; "¶" ] ) ; 1 ) ; ~hostLength = Length ( ~host ) ; ~url = Middle ( ~url ; ( ~hostLength + 1 ) ; ~urlLength ) ; // port ~port = GetAsNumber ( GetValue ( Substitute ( ~url ; [ "/" ; "¶" ] ; [ "?" ; "¶" ] ; [ "#" ; "¶" ] ) ; 1 ) ) ; ~portLength = Length ( ":" & ~port ) ; ~url = If ( not IsEmpty ( ~port ) ; Middle ( ~url ; ( ~portLength + 1 ) ; ~urlLength ) ; ~url ) ; // path ~path = GetValue ( Substitute ( ~url ; [ "?" ; "¶" ] ; [ "#" ; "¶" ] ) ; 1 ) ; ~pathLength = Length ( ~path ) ; ~url = If ( not IsEmpty ( ~path ) ; Middle ( ~url ; ( ~pathLength + 1 ) ; ~urlLength ) ; ~url ) ; // file ~pathList = Substitute ( ~path ; "/" ; "¶" ) ; ~pathListLast = GetValue ( ~pathList ; ValueCount ( ~pathList ) ) ; ~fileName = If ( GetAsBoolean ( PatternCount ( ~pathListLast ; "." ) ) ; ~pathListLast ; "" ) ; // query ~isQuery = GetAsBoolean ( Left ( ~url ; 1 ) = "?" ) ; ~query = GetValue ( Substitute ( ~url ; [ "?" ; "" ] ; [ "#" ; "¶" ] ) ; 1 ) ; ~queryLength = Length ( "?" & ~query ) ; ~url = If ( ~isQuery ; Middle ( ~url ; ( ~queryLength + 1 ) ; ~urlLength ) ; ~url ) ; // fragment ~fragment = GetValue ( Substitute ( ~url ; [ "#" ; "¶" ] ) ; 2 ) ; ~fragmentLength = Length ( "#" & ~fragment ) ; ~url = If ( not IsEmpty ( ~fragment ) ; Middle ( ~url ; ( ~fragmentLength + 1 ) ; ~urlLength ) ; ~url ) ; // check ~urlIsEmpty = If ( IsEmpty ( ~url ) ; True ; False ) ] ; JSONSetElement ( "" ; [ "scheme" ; ~scheme ; JSONString ] ; [ "userName" ; ~userName ; JSONString ] ; [ "password" ; ~password ; JSONString ] ; [ "host" ; ~host ; JSONString ] ; [ "port" ; ~port ; JSONString ] ; [ "path" ; ~path ; JSONString ] ; [ "fileName" ; ~fileName ; JSONString ] ; [ "fragment" ; ~fragment ; JSONString ] ; [ "query" ; ~query ; JSONString ] ; [ "urlIsEmpty" ; ~urlIsEmpty ; JSONBoolean ] ) ) /*Let*/
サンプル
ParseUrl ( "https://username:[email protected]:80/dir1/file.txt?q1=v1&q2=v2#fragment" ) ---------- { "fileName": "file.txt", "fragment": "fragment", "host": "bucketname.s3.ap-northeast-1.amazonaws.com", "password": "password", "path": "/dir1/file.txt", "port": "999", "query": "q1=v1&q2=v2", "scheme": "https", "urlIsEmpty": true, "userName": "username" }
ParseUrl ( "https://www.briandunning.com/cf/2627" ) ---------- { "fileName": "", "fragment": "", "host": "www.briandunning.com", "password": "", "path": "/cf/2627", "port": "", "query": "", "scheme": "https", "urlIsEmpty": true, "userName": "" }
バグなど見つかりましたら、コメント頂ければと思います。