AWS Cognito ページネーショントークンで全ユーザーを取得する

# list_users( ) にはlimitがあった

100以上ユーザーを登録しているのに、list_users後のresponseを見ていたら存在するはずのメールアドレスが表示されていないことに気づいた。そこでログを出してみると、、、なぜか60人しか取れていなかった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/e8497bc2-c09b-98f2-de18-7ef6dde422de.png)

Boto3 Docsには以下の記述がある。

> Limit (integer) -- Maximum number of users to be returned.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/848148c8-ef5d-f2fa-849e-397bb56e7678.png)

最大値を引数で指定できる。試しに`Limit=200`にすると、

```
Value '200' at 'limit' failed to satisfy constraint: Member must have value less than or equal to 60
```

60までしか指定できないとのこと。デフォルトですでに最大数に達していた。

> PaginationToken (string) -- An identifier that was returned from the previous call to this operation, which can be used to return the next set of items in the list.

> 前の検索からさらに結果を取得するためのトークンです。

この**ページネーショントークン**がここから活躍する。list_users()の引数に、前回のlist_users()のレスポンスに含まれる`PaginationToken`を与えると、まだ取得していないユーザーを返してくれる。ただし、これ以上次のユーザーがいない場合、`PaginationToken`はレスポンスに含まれない。つまり、すべてのユーザーを取得したかどうかは、`PaginationToken`がレスポンスに含まれているかどうかを見ればよい。


# サンプルコード

以下のコードはページネーショントークンを使って全ユーザーを取得する。特に`get_user_list()`でトークンを使っている。

```lambda_function.py
import boto3
import json


def get_user_list(event):
    client = boto3.client('cognito-idp')
    # 最初のユーザー取得時はページネーション引数を指定しないこと
    # botocore/validate.pyで例外として処理される
    response = client.list_users(
        UserPoolId='ap-northeast-1_XXXXXXXXXX'
    )

    user_datas = []
    append_user_dict(response, user_datas)
    while True:
        # ページネーショントークンがレスポンスに含まれなくなったらループ終了
        if 'PaginationToken' not in response:
            break
        # 前回のレスポンスに含まれるページネーショントークンを渡す
        response = client.list_users(
            UserPoolId='ap-northeast-1_XXXXXXXXX',
            PaginationToken=response['PaginationToken']
        )
        append_user_dict(response, user_datas)
    return user_datas


def append_user_dict(response, user_datas):
    """
    ユーザー名とメールアドレスを辞書型で取得し、user_datasに追加するメソッド
    """
    for x in response['Users']:
        user_data = {}
        user_data['Username'] = x['Username']
        user_data['email'] = get_email(x['Attributes'])
        user_datas.append(user_data)


def get_email(attr_list):
    """
    レスポンスに含まれる各ユーザー情報からメールアドレスを抽出するメソッド
    """
    for x in attr_list:
        if x['Name'] == 'email':
            return x['Value']
    return None


def lambda_handler(event, context):
    """
    True：クライアントのメールアドレスが
          まだユーザープールに登録されていない
    False：クライアントのメールアドレスが
           すでにユーザープールに登録されてるいる
    """
    user_datas = get_user_list(event)
    # user_datasを出力
    print(user_datas)
    return (event['email'] not in
            [user_data['email'] for user_data in user_datas])

```

user_datasの結果

```
[{'Username': 'dummy-user-557', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-558', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-559', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-560', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-561', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-562', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-563', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-564', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-565', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-566', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-567', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-568', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-569', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-570', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-571', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-572', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-573', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-574', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-575', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-576', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-577', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-578', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-579', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-580', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-581', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-582', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-583', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-584', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-585', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-586', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-587', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-588', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-589', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-590', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-591', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-592', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-593', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-594', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-595', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-596', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-597', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-598', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-599', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-600', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-601', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-602', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-603', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-604', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-605', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-606', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-607', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-608', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-609', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-610', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-611', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-612', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-613', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-614', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-615', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-616', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-617', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-618', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-619', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-620', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-621', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-622', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-623', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-624', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-625', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-626', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-627', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-628', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-629', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-630', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-631', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-632', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-633', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-634', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-635', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-636', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-637', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-638', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-639', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-640', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-641', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-642', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-643', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-644', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-645', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-646', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-647', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-648', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-649', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-650', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-651', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-652', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-653', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-654', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-655', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-656', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-657', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-658', 'email': 'xxxxxxxx@yyyy.com'}, {'Username': 'dummy-user-659', 'email': 'xxxxxxxx@yyyy.com'}]
```

# 参考記事

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cognito-idp.html#CognitoIdentityProvider.Client.list_users

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/how-to-manage-user-accounts.html

https://github.com/boto/botocore/tree/develop/botocore