(Power BI) Mから始めよう #10 エラー処理とHTTPステータスコード


（この記事は、2021/12/08に執筆しました）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/2e1575d6-13a8-dd62-dc47-a396c0121640.png)

https://bengribaudo.com/blog/2020/01/15/4883/power-query-m-primer-part-15-error-handling

https://docs.microsoft.com/ja-jp/power-query/handlingerrors

https://docs.microsoft.com/ja-jp/powerquery-m/m-spec-error-handling

　エラーが発生しないように記述する方がいいのですが、エラーの発生がどううしようもない場合、わざと発生させる場合などあります。エラーの発生の仕方と、対応方法を検討します。

# １．エラーの発生のさせ方

　errorを使ってエラーを発生させます。

```:sample1-1
let
    Output = error "エラーメッセージ"
in
    Output
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/874016d1-5599-c30d-f82e-4d178e1d4fe6.png)

　エラーメッセージだけでなく、詳細を付けることもできます。

```:sample1-2
let
    Output = 
        error Error.Record(
            "ファイル読み込みエラー", 
            "ファイル名my.txtが見つかりません",
            "my.txt"
        )
in
    Output
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/ddd86b49-2187-359c-5d01-0eac9676d52b.png)

　以下の書き方もできます。

```:sample1-3
let
    Output = 
        error [
            Reason = "ファイル読み込みエラー", 
            Message = "ファイル名my.txtが見つかりません",
            Detail = "my.txt"
        ]
in
    Output
```

# ２．tryとotherwiseによってエラーをつかまえる
　tryの後の処理でエラーが発生した場合、処理を中断せずにotherwiseの処理に移ります。以下の例では、"foo"という文字列に１を加算しようとしているので、エラーとなります。

```:sample2-1
try "foo"+1
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/57976ce0-ce6b-d9d3-f6a8-838aa95cc275.png)

　otherwiseをつかって、このエラーを処理します。

```:sample2-2
try 
    "foo"+1 
otherwise 
    "エラー発生"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/8874d16b-5c90-bd8f-ed0e-758f32d3e84f.png)

　tryで返される値は、2-1でやったように、**[HasError]**にエラーが発生したかどうかのブーリアン型の値が入ります。
　エラーが発生していた場合は**[Error]**の中に**Reason**、**Message**、**Detail**がレコードとして入っています。

```:sample2-3
let
Result = try "foo"+1,
Output = 
    if Result[HasError] then 
        "エラーメッセージ：" & Result[Error][Message]
    else 
        Result[Value]
in
    Output
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/b3337a43-279e-534d-3e4a-331db2259773.png)

# ３．エラー抑制(Error Containment)
　エラーが発生すると、エラーの発生した値にアクセスする部分にのみ影響し、影響しない部分は最後まで実行されます。

```:sample3-1
let
    Source = NotDefine(),
    Result = [
        Value1 = 25,
        Value2 = Source,
        Value3 = Value1 + Value2
    ]
in
    Result
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/263ebb99-1758-8805-4b17-928432352343.png)

　Sourceの値はエラーとなりますが、最後まで実行されて、Result[Value1]の値は25と表示されます。
　また、エラーが発生していても、その式が評価されなければ、何の影響も発生しません。下の例では、行の数を計算するのに項目の値は関係ないため、正常に値を返します。

```:sample3-2
let
  Data = #table({"Col1"}, {{"SomeValue"}, { error "bad" }})
in
  Table.RowCount(Data)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/7d3055de-f5fd-1278-6c9e-e4599c19a8a4.png)

# ４．スコープ
　下の例では、テーブルの中の値の１つでエラーが発生しており、このコードは0を返すことを期待していますが、結果的にエラーを含むテーブルとして値が返されます。
　テーブル内のセルで発生したエラーは、テーブルの式レベルには影響を与えません。

```:sample4-1
let
  Data = #table({"Amount"}, {{10}, {error "help!"}, {error "save me!"}})
in
  try Data otherwise 0
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/4af96dcb-82d6-fd80-dbe8-cd44246ce111.png)

　一方、次の式では、最後にList.Sumでテーブル内のセルの値を評価しているため、エラーが発生し、0が返されます。

```:sample4-2
let
  Data = #table({"Amount"}, {{10}, {error "help!"}, {error "save me!"}})
in
  try List.Sum(Data[Amount]) otherwise 0
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/6918086f-148d-52ef-fcfc-6738c0d6d3a6.png)

　参考に、エラーを0に置き換えて集計するには、以下のようにやります。

```:sample4-3
let
    Data = 
        #table(
            {"Amount"}, 
            {
                {10}, 
                {error "help!"}, 
                {error "save me!"}
            }
        ),
    // 項目NewAmountを追加し、Amountの値を入れる。ただし、エラーの場合は0にする。
    ErrorsReplacedWithZero = 
        Table.AddColumn(
            Data, 
            "NewAmount", 
            (row) => try row[Amount] otherwise 0
        ),
    // 項目Amountを削除
    RemoveOldAmount = 
        Table.RemoveColumns(
            ErrorsReplacedWithZero, 
            {"Amount"}
        ),
    // 項目名をNewAmountからAmountに変更
    RenameNewAmount = 
        Table.RenameColumns(
            RemoveOldAmount, 
            {
                "NewAmount", 
                "Amount"
            }
        )
in
    List.Sum(RenameNewAmount[Amount]) // returns 10
```

# ５．Webコンテンツのレスポンスコードを取得する

https://docs.microsoft.com/ja-jp/power-query/handlingstatuscodes

https://www.myonlinetraininghub.com/handling-http-errors-in-power-query-and-power-bi

 Web,Contentsで404(Not Found)を発生させます。

```:sample5-1
let
    response = try Web.Contents(url)
in
    response
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/99894dd7-5886-b097-654f-6b52f6e87af5.png)

 Web.Contentsではエラーが帰ってきません。Valueの中にステータスコードが入っているようです。以下のように、ManualStatusHandling、Metadataを使ってレスポンスコードを取り出します。

```:sample5-2
let
    Source = Web.Contents(url, [ManualStatusHandling={400,404,500}]),
    // 400 Bad Request, 404 Not Found, 500 Internal Server Error
    Response = Value.Metadata(Source)
in
    Response
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/550d8156-e8a5-07ee-0cbf-fcca651ea9f3.png)

レスポンスコードは、 Response.Statusにあることがわかります。

```:sample5-3
let
    response = Web.Contents(url, [ManualStatusHandling={400,404, 500}]),
    // 400 Bad Request, 404 Not Found, 500 Internal Server Error
    responseCode = Value.Metadata(response)[Response.Status]
in
    responseCode
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/6829d6e8-baa5-8e30-de97-2aff9075d96e.png)

　レスポンスコードを取り出すには、以下のようにします。

```:sample5-4
let
    Source = Web.Contents(#"url", [ManualStatusHandling={400,404,500}]),
    ResponseCode = Value.Metadata(Source)[Response.Status]
in
    ResponseCode
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/04e43006-5344-97a0-2980-66db4c96a2c1.png)


# Try & Catch
https://qiita.com/spumoni/items/d3b127c7b326497e20df

# 関連記事

- [Mから始めよう #5 〜Power BIでWebコンテンツの利用と個人用ゲートウェイ〜](https://qiita.com/spumoni/items/f66bb43f0c3f13308d79)
- [[Power BI] Power Query の Web.Contents 関数でREST APIを使う](https://qiita.com/spumoni/items/419ffd1f07947a07cad0)
- [(Power BI) Mから始めよう #8 〜クエリ・パラメータの各種使い方](https://qiita.com/spumoni/items/4badf29d0b3e170fa15b#b%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E9%96%A2%E6%95%B0%E3%81%A8url%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%81%A7web%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0)
- [ページ分割されているWebでページ数がわからないデータを取得する](https://qiita.com/spumoni/items/2832b63fa627b20a5de2#4-%E3%83%9A%E3%83%BC%E3%82%B8%E5%88%86%E5%89%B2%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8Bweb%E3%81%A7%E3%83%9A%E3%83%BC%E3%82%B8%E6%95%B0%E3%81%8C%E3%82%8F%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B)
- [(Power BI) Mから始めよう #10 エラー処理とHTTPステータスコード](https://qiita.com/spumoni/items/cd5843e0104fed9b4874)
- [[Power BI] Power QueryでCSSセレクタを使ってWebページからデータを取得する](https://qiita.com/spumoni/items/cad005c1deaa522531d8)