Lambda(Node.js)からS3のファイルにアクセスする連携方法

Lambda(Node.js)からS3のファイルにアクセスする連携方法

Lambda(Node.js)からS3のファイルにアクセスする方法です。

S3とは単なるファイルストレージです。ウィンドウズのエクスプローラと同じでC:\a\b\cみたいな構造でファイルなどを置くことができます。

S3にバケットを作成します。Cドライブみたいなものとイメージして差し支えないと思います。

Lambda(Node.js)からS3のファイルにアクセスする連携方法

「バケットを作成する」をクリックします。

Lambda(Node.js)からS3のファイルにアクセスする連携方法

ここでは、「sde」というバケットを作成しました。

sdeにアクセスすると、フォルダの作成ができますので作成してみます。

Lambda(Node.js)からS3のファイルにアクセスする連携方法

ここでは「a」というフォルダを作成しました。さらにa/b/cというようにフォルダを作成します。

Lambda(Node.js)からS3のファイルにアクセスする連携方法

これで、sdeというバケットにa/b/cというフォルダ構造を作成することができました。

この配下にJSONオブジェクトが定義してある.jsonファイルを配置してみます。

「アップロード」をクリックします。

Lambda(Node.js)からS3のファイルにアクセスする連携方法

ローカルにあるファイルをこのウィンドウにドラッグアンドドロップします。

Lambda(Node.js)からS3のファイルにアクセスする連携方法

ファイルを置くと上記のようになるので「次へ」をクリックします。

Lambda(Node.js)からS3のファイルにアクセスする連携方法

そのまま「次へ」をクリックします。

Lambda(Node.js)からS3のファイルにアクセスする連携方法

「次へ」をクリックします。

Lambda(Node.js)からS3のファイルにアクセスする連携方法

「アップロード」をクリックします。

Lambda(Node.js)からS3のファイルにアクセスする連携方法

これで、sdeというバケットのa/b/cフォルダ配下にsample.jsonをアップロードすることができました。

次はlambdaからs3ファイルへアクセスする例です。ファイル一覧を取得するにはlistObjectsV2メソッドを使います。

const AWS = require('aws-sdk');
const s3 = new AWS.S3({'region':'ap-northeast-1'});

exports.handler = (event, context, callback) => {
  let params = {
    'Bucket': 'sde',
    'Prefix': 'a/b/c'
  }
  s3.listObjectsV2(params, function(err, data) {
    data.Contents.forEach(function(elem){
      console.log(elem.Key);
    });
    response = data.Contents;
    callback(null, response);
  });
};

バケットsdeの/a/b/c/配下のjsonファイルだけ取得できると思ったのですが、フォルダが取れて、さらにそのフォルダ内のファイルが取れてきてしまいます。

[
  {
    "Key": "a/b/c/",
    "LastModified": "2017-12-03T00:06:15.000Z",
    "ETag": "\"d41d8cd98f00b204e9432298ecf8427e\"",
    "Size": 0,
    "StorageClass": "STANDARD"
  },
  {
    "Key": "a/b/c/sample.json",
    "LastModified": "2017-12-03T00:19:39.000Z",
    "ETag": "\"593902c4008cdb4c567342badee01680\"",
    "Size": 41,
    "StorageClass": "STANDARD"
  }
]

フォルダ配下のファイルだけ取得したい場合はStartAfterを指定する

Contents.Keyにフォルダが取れてきてしまうわけですが不要だ、という場合はStartAfterを指定します。StartAfterはAWS S3はこの指定されたキーの後のリストを取得します。

const AWS = require('aws-sdk');
const S3 = new AWS.S3({'region':'us-east-1'});

exports.handler = (event, context, callback) => {
  let params = {
    'Bucket': 'sde',
    'Prefix': 'a/b/c/',
    'StartAfter':'a/b/c/' // a/b/c/配下だけを取得する
  }
  S3.listObjectsV2(params, function(err, data) {
    data.Contents.forEach(function(elem){
      console.log(elem.Key);
    });
    response = data.Contents;
    callback(null, response);
  });
};

結果は以下のようにファイルのフルパスのみ取得されます。(これでも問題があります)

[
  {
    "Key": "a/b/c/sample.json",
    "LastModified": "2017-12-03T00:19:39.000Z",
    "ETag": "\"593902c4008cdb4c200892badee01680\"",
    "Size": 41,
    "StorageClass": "STANDARD"
  }
]

参考サイト

マネジメントコンソールからフォルダを作成しない(結論)

StartAfterを指定してもその配下にフォルダが存在する場合は、a/b/c/dというようなフォルダが取得されてしまいます。これはフォルダは0バイトのオブジェクトだからです。

プログラムや、CLIのcpなどでファイルをアップロードすれば0バイトのフォルダはそもそも作成されないので、CLIでファイルをアップロードすれば解決します。

もしマネジメントコンソールからフォルダを作成してしまった場合は、フォルダ=オブジェクトなのでrmコマンドで削除すればよいです。

バケットは以下の全フォルダ(オブジェクト)を削除するコマンド例です。

aws s3 rm s3://バケット名/ --exclude '*.*' --recursive

間違って全オブジェクトが来得てしまって困る場合などは、最後に--dryrunオプションをつけて確認してから実行すればよいです。

listObjectsV2で取得できるオブジェクトは最大1000件

listObjectsV2で取得できるオブジェクトは最大1000件です。1000件以上オブジェクトが存在する場合は、NextContinuationTokenにトークンが設定されます。IsTruncated=trueとなります。

次の1000件を取得する場合にlistObjectsV2の引数にContinuationToken: トークンを指定します。最後の1000件になった場合にIsTruncated=falseとなります。

1000件はデフォルト値(最大値)なので、listObjectsV2の引数にMaxKeys: 100などして1回で取得する最大件数を変更することができます。但し、1001以上の値を指定しても最大1000件となります。

AWS-SDKのs3.putObjectメソッドでファイルをアップロードする(node.js v12.x)

s3にはputObjectメソッドがあり、このメソッドを使ってS3バケットの指定したオブジェクトキーでファイルをアップロードすることができます。

const AWS = require('aws-sdk');
const s3 = new AWS.S3({'region':'ap-southeast-1'});
AWS.config.update({region: 'ap-southeast-1'});

exports.handler = async (event) => {
  const params = {
    Bucket:'test-bucket',
    Key:'dir1/subdir1/sample.json',
    Body: JSON.stringify({name: 'takahashi', age: 50},undefined,1),
    ContentType: 'application/json'
  }
  const json = await s3.putObject(params).promise().catch(err=>{
    throw new Error(`エラー`)
  })
}

今回はJSONファイルなので、ContentType: 'application/json'としています。

Bucketにバケット名、Keyにオブジェクトキー名を指定します。

sample.jsonの中身は、Bodyで指定します。この時、文字列にしないといけません。(JSONファイルの場合)

その為、JSON.stringifyをしていますが、オブジェクトとして整形するために、第二引数、第三引数を指定してあげます。

引数
第一 オブジェクト
第二 undefined
第三 1

これでS3にアップロードされたファイルがオブジェクト形式になっていることが確認できます。

Lambda(Node.js)からS3のファイルにアクセスする連携方法

これは見た目上の問題であって、s3のgetObjectで取得する際はJSON.parse(file.Body)としてあげないといけません。

0バイトのファイルをputする

0バイトのファイルをputObjectで作成する場合は、Bodyプロパティの値をnullにすれば0バイトのファイルをputすることが出来ます。””とすると2Byteのファイルが出来てしまいます。

const AWS = require('aws-sdk');
const S3 = new AWS.S3({'region':'us-east-1'});

exports.handler = async (event) => {
  const param = {
    'Bucket': 'bucketname',
    'Key': 'var/tmp/a.json',
    'Body': null // nullにしておく
  }
  await S3.putObject(param).promise()
}

AWS-SDKのs3.deleteObjectメソッドで存在しないファイルを削除してもエラーにならない(node.js v12.x)

getObjectなどでファイルが存在しない場合、エラーとなりますが、deleteObjectメソッドで存在しないファイルを削除してもエラーにはならないようです。

以下、実行例です。await – catchのcatchには入りません。

const AWS = require('aws-sdk');
const s3 = new AWS.S3({'region':'ap-southeast-1'});
AWS.config.update({region: 'ap-southeast-1'});

exports.handler = async (event) => {

  const deletes = await s3.deleteObject(
    {
      Bucket:'test-bucket', // 存在するバケット
      Key:'test/sample.json' // 存在しないファイル
    }).promise().catch(err=>{
      throw new Error(err) // test/sample.jsonが存在しなくてもcatch句には入らない
    })
}

deleteObjectメソッドでは存在しないバケットを指定した場合にはcatch句に入ります。

const AWS = require('aws-sdk');
const s3 = new AWS.S3({'region':'ap-southeast-1'});
AWS.config.update({region: 'ap-southeast-1'});

exports.handler = async (event) => {

  const deletes = await s3.deleteObject(
  {
    Bucket:'test-bucketxxx', // 存在しないバケット
    Key:'test/sample.json'
  }).promise().catch(err=>{
    throw new Error(err) // catch句に入る
  })
}

コメント

タイトルとURLをコピーしました