92497


###### 質問内容

リファレンスサイトの`GET https://mastodon.example/api/v1/timelines/list/:list_id
HTTP/1.1`でリストのタイムラインが取得できない原因が知りたい

##### 試したこと

他のwebclient系の処理は成功しているため通信は成功しています。

コメント部のように`URL`を様々な形に変更して実験

他の`webclient`系の通信処理が正常に行われるためエージェント等の処理は成功しています。

コマンドプロンプトの出力がStatusCodeがＯＫ以外場合が来ているので値を確認しています。

`list_id`はwebブラウザ上のものと同じため正しいです

`参考コード`は自分で記述して正常に動作しているのですがこれとまったく同じことをやっているので取得出来ているはずなので取得出来ません。

リファレンス(View list timeline)：https://docs.joinmastodon.org/methods/timelines/

##### コマンドプロンプト

[code]

    10819
    mstdn.jp
    list_id=10819&Authorization=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    NotFound
    
[/code]

##### ソースコード

[code]

    
            /*##################################################################################################################
             * リストタイムライン 取得
            ###################################################################################################################*/
            public async Task<List<JsonData.Post>?> getListTimeLine_Asnyc(string listID, string? max_id, string? since_id, string? min_id, string? limit)
            {
                //var response = await client.GetAsync("https://" + instance + "/api/v1/timelines/list/:" + Method_Parameter.GetListTimeLine(listID,token,null, null, null, null).ReadAsStringAsync().Result);
                //var response = await client.GetAsync("https://" + instance + "/api/v1/timelines/list/:list_id?" + Method_Parameter.GetListTimeLine(listID,token,null, null, null, null).ReadAsStringAsync().Result);
                //var response = await client.GetAsync("https://" + instance + "/api/v1/timelines/list/" + Method_Parameter.GetListTimeLine(listID,token,null, null, null, null).ReadAsStringAsync().Result);
                //var response = await client.GetAsync("https://" + instance + "/api/v1/timelines/list/?" + Method_Parameter.GetListTimeLine(listID,token,null, null, null, null).ReadAsStringAsync().Result);
                var response = await client.GetAsync("https://" + instance + "/api/v1/timelines/list/" + Method_Parameter.GetListTimeLine(listID,token,null, null, null, null).ReadAsStringAsync().Result);
                var response = await client.GetAsync("https://" + instance + "/api/v1/timelines/list/:list_id" + Method_Parameter.GetListTimeLine(listID,token,null, null, null, null).ReadAsStringAsync().Result);
    
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    var notice = await response.Content.ReadFromJsonAsync<List<JsonData.Post>>();
    
                    List<JsonData.Post> list = new List<JsonData.Post>();
                    foreach (JsonData.Post n in notice)
                    {
                       
    
                        list.Add(n);
                    }
    
                    return list;
                }
                else
                {
                    Console.WriteLine(listID);
                    Console.WriteLine(instance);
                    Console.WriteLine(Method_Parameter.GetListTimeLine(listID, token, null, null, null, null).ReadAsStringAsync().Result);
                    Console.WriteLine(response.StatusCode);
                    return null;
                }
    
                return null;
    
            }
    
    
[/code]

[code]

            /*##################################################################################################################
             * リストタイムライン　取得
            ###################################################################################################################*/
            static public FormUrlEncodedContent GetListTimeLine(string listID,string token, string? max_id, string? since_id, string? min_id, string? limit)
            {
                var parameter = new Dictionary<string, string>();
    
                parameter.Add("list_id", listID);
                //parameter.Add(":list_id", listID);
                parameter.Add("Authorization", token);
    
    
                if (max_id != null)
                {
                    parameter.Add("max_id", max_id);
                }
    
                if (since_id != null)
                {
                    parameter.Add("since_id", since_id);
                }
    
                if (min_id != null)
                {
                    parameter.Add("min_id", min_id);
                }
    
                if (limit != null)
                {
                    parameter.Add("limit", limit);
                }
    
                return new FormUrlEncodedContent(parameter);
            }
    
[/code]

##### 参考コード

[code]

            /*##################################################################################################################
             * 通知一覧を取得
            ###################################################################################################################*/
            public async Task<List<Notice>?> getNotics_Asnyc()
            {
                var response = await client.GetAsync("https://" + instance + "/api/v1/notifications?" + Method_Parameter.GetNotics(token,null,null,null,null,null,null).ReadAsStringAsync().Result);
                
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    var notice = await response.Content.ReadFromJsonAsync<List<JsonData.Notice>>();
    
                    List<Notice> list = new List<Notice>();
                    foreach(JsonData.Notice n in notice)
                    {
                        Notice nn = new Notice(n);
                       
                        list.Add(new Notice(n));
                    }
                    
                    return list;
                }
                else
                {
                    Console.WriteLine("getList_Async()  " + response.StatusCode);
    
                    return null;
                }
    
                return null;
    
            }
    
    
[/code]


CC BY-SA 4.0
2022-11-28T08:15:53.273
92477
2022-11-29T10:19:30.650
2022-11-29T00:02:06.377
55177
55177
question
c#
「GET https://mastodon.example/api/v1/timelines/list/:list_id HTTP/1.1」が取得できない原因が知りたい。


##### 原因

パスパラメータ、クエリパラメータ、ヘッダーがそれぞれ別のものであるとういことを見落としていました。結果リファレンスサイト通り以下のURLをＧＥＴすることにより取得出来ました。

[code]

     var response = await client.GetAsync("https://" + instance + "/api/v1/timelines/list/"+listID);
    
[/code]


CC BY-SA 4.0
2022-11-29T10:07:32.200
92496
2022-11-29T10:07:32.200
55177
92477
answer


APIアクセスできるようになるには、[リファレンス](https://docs.joinmastodon.org/methods/timelines/#list)の内容を理解して、アクセスすべきURLがどのようになるのかを自分で組み立てられるようにならなければなりません。原因は「リファレンスの理解不足」です。ですので、コードをいくら直そうが、正しいURLにはいつまで辿り着けないため、解決することはありません。

MastodonのAPIの使い方は[Getting started with the
API](https://docs.joinmastodon.org/client/intro/)に書いていますが、一般的なREST
APIを知っている人向けに書かれています。一般的なREST APIとは異なるかも知れない細部(そのほとんどはMastdonが作られたRuby on
Rails特有のもの)が述べられています。もし、Ruby on Railsを知らないのであれば、一読しておく必要があります。その上で、API
リファレンス側を確認し、どのようなURLでアクセスすべきなのかを考えます。

まず、URLが構成する要素について、きちんと知っているでしょうか？もし、知らないというのであれば、この先を読んでも理解はできません。その場合は、書籍などで勉強し直してください。

URLは大きく分けて次の要素からなります。(これに加えて「ハッシュ」がありますが、今回は扱わないので省略します。)

  * スキーム
  * ホスト(ユーザー情報とポートがついている場合がある)
  * パス
  * クエリ

これを使ってURLを表すと`【スキーム】://【ホスト】【パス】?【クエリ】`という形です。では、リファレンスではこれらは、どのようになっているでしょうか？`GET
https://mastodon.example/api/v1/timelines/list/:list_id HTTP/1.1`なので

  * スキーム: `https`
  * ホスト: `mastodon.example.com`
  * パス: `/api/v1/timelines/list/:list_id`
  * クエリ: なし？

いいえ違います。

まず、ホストは例では無く実際のサーバーになります。Mastdonは色々なサーバーがあるので、実際に使っているサーバーによって変わると言うことです。ここらへんはわかるかと思いますが、Twitterのような一つのサービスの場合はホストは不変だったりします。

次にパスですが、ここに、このリファレンスがある程度REST
APIを知っている人向けに書かれているといえる所があります。パスのところで`:list_id`というのがありますが、
**パスに`:`をそのまま書くことはできません。** もし、REST APIに詳しくなくても、これは **そのままパスの文字列にはできない**
ということに気付かなければなりません。では、`:list_id`は何かというと、パスの中に含まれるパラメーター「パスパラメーター/Path
paramaters」というものです。では、どんな値になるのかはすぐしたの[Path
parameters](https://docs.joinmastodon.org/methods/timelines/#path-
parameters-1)に書いています。リストのIDが文字列としてそのまま入ると言うことです。どういうことかというと、もし、リストのIDが42の場合は、パスは`/api/v1/timelines/list/42`になるということです。

最後にクエリですが、`GET`から始まるところにはクエリはありませんでした。ですが、クエリを付けられないという事ではありません。[Query
parameters](https://docs.joinmastodon.org/methods/timelines/#query-
parameters-3)に追加できるクエリがあります。たとえば、`limit`を30にしたいなら`limit=30`とクエリを追加できます。

では、リストのIDが42に対して、30個までを取る場合は具体的にどうなるのかを見ていきましょう。ホストは例のままにします。

  * スキーム: `https`
  * ホスト: `mastodon.example.com`
  * パス: `/api/v1/timelines/list/42`
  * クエリ: `limit=30`

URLは次のようになります。

`https://mastodon.example.com/api/v1/timelines/list/42?limit=30`

このようなURLへアクセスする必要があります。まずは、URLとなる文字列を生成し、それが想定通りの値になっているかを`Console.WriteLine()`等で確認してください。

最後に、ヘッダーに認可トークン(`Authorization`)が含まれる必要がありますが、他ができていれば、たぶんできているでしょう。

* * *

なお、既に[C#のライブラリ](https://docs.joinmastodon.org/client/libraries/#c-net-
standard)があるので、自分で組むのは車輪の再発明だし、こちらを組み込んだ方が早いと思います。もし、REST
APIの勉強のためというのであれば、Qiita APIとか日本語の解説がついているもののほうが最初はやりやすいと思います。


CC BY-SA 4.0
2022-11-29T10:19:30.650
92497
2022-11-29T10:19:30.650
7347
92477
answer