ExpressでS3からCSVファイルのデータを取得（ついでにSSMパラメータを取得）する方法簡易メモ

## やりたいこと
idList.csvというCSVファイルをS3に格納
ExpressでS3からidList.csvファイルのデータを取得
idList.csvファイルを格納しているバケット名はSSMで管理

※idList.csvファイルの中身はこんな感じ
![スクリーンショット 2023-01-11 23.13.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566220/9a57605a-02af-a880-585a-e8f7d6d4b61b.png)

## S3にファイルアップロード
Amazon S3 > Buckets > Create bucket
でバケットを(ap-northeast-1で)作成し、idList.csvファイルをアップロードする

![スクリーンショット 2023-01-11 23.11.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566220/fa92b5de-830e-1ad1-d461-97f6b11353ec.png)
バケット名は伏せている

## バケット名をSSMパラメータで定義する ※jsのコードにベタ書きでよければ不要
AWS Systems Manager > Parameter Store > Create parameter

BUCKET_NAME_ID_LISTというキーに先程作成したバケット名を登録した
![スクリーンショット 2023-01-11 23.10.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566220/a785d77b-13ff-b99e-0ee3-2d72d79913a1.png)

## jsコード
`% npm i @aws-sdk/client-s3 aws-sdk` ※typescriptに必要なパッケージは省略（後述のgithubに記述）

```index.ts
import express from 'express';
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { SdkStream } from '@aws-sdk/types';
import { Readable } from 'stream';
import AWS from 'aws-sdk';

const app = express();
const port = 3000;

const ssm = new AWS.SSM({ region: 'ap-northeast-1' });
const s3Client = new S3Client({ region: 'ap-northeast-1' });

// 取得したCSVのデータストリームをListに変換
const streamToList = (stream: SdkStream<Readable>): Promise<string[]> =>
    new Promise((resolve, reject) => {
        const items: string[] = [];
        const splitter = /[\r\n]+/;
        let leftOver = '';

        const toItems = (data: string[]): string[] => data.filter((line) => line.trim()).map((id) => id);

        stream.on('data', (chunk: Uint8Array) => {
            const data = `${leftOver}${chunk.toString()}`.split(splitter);
            leftOver = data.pop() || '';
            items.push(...toItems(data));
        });
        stream.on('error', reject);
        stream.on('end', () => resolve(items.concat(leftOver ? toItems(leftOver.split(splitter)) : [])));
    });

export async function getIdListFromS3(): Promise<string[]> {
    try {
        // SSMからバケット名取得
        const { Parameter } = await ssm
            .getParameter({
                Name: 'BUCKET_NAME_ID_LIST',
                WithDecryption: true,
            })
            .promise();
        // S3からCSVファイルデータ取得取得
        const { Body } = await s3Client.send(
            new GetObjectCommand({
                Bucket: Parameter?.Value,
                Key: 'idList.csv',
            })
        );
        return await streamToList(Body as SdkStream<Readable>);
    } catch (e) {
        console.error(`List取得でエラー発生:${(e as Error).message}`, e);
        return [];
    }
}

app.get('/', async (req, res) => {
    const ids = await getIdListFromS3();
    res.send(ids);
});
app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
});
```

## 参考
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-s3/index.html

https://dev.classmethod.jp/articles/aws-sdk-for-javascript-v2-v3-diff/

https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/index.html

## 動作確認

![スクリーンショット 2023-01-11 23.19.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566220/469be583-a12a-6f72-3b3b-813dcb336325.png)

コード全体、バージョン情報等はこちら

https://github.com/yamatoto/s3-server