NBBとラムダ関数のURL:ケーキの一部に退屈なタスクを回します.


ハイ👋, ユージンは、ここにいます.
数週間前に私はtalk 与えられるnbb - ノード上のアドホックCLJSスクリプトのためのツールjs
私は本当に彼のプレゼンテーションが好きだったので、私は離れてから理論と実践から新しい知識を移行する準備ができました.それで、あなたが私が終わったものを知っている好奇心が強いならば、飛び込んでください.
私のチームでは、実験の文化を促進します.それはさらに重要なプロジェクト分野で新しいことをしようとするための素晴らしい機会を作成します.
そのような実験のために、私はしばしば何かを明確な結果や何度も実装している何かを選択しようとします.内部のサービスの1つはノードを使用します.が生成するpresigned URLs ファイルアップロード用.かなり退屈な標準的なこと.書き換えのための完璧な候補のような音ですね?
プロジェクトは新しいモジュラーアーキテクチャを持つJavaScript V 3のためにAWS SDKを使用します.だからpackage.json つのライブラリが含まれます@aws-sdk/client-s3 and @aws-sdk/s3-presigned-post 輸入するS3 クライアントとcreatePresignedPost プリサインされたURLを生成するメソッドです.また、追加する必要がありますnbb 依存関係として.満席package.json ファイルは以下のようになります:
{
   "dependencies": {
       "@aws-sdk/client-s3": "^3.67.0",
       "@aws-sdk/s3-presigned-post": "^3.67.0",
       "nbb": "^0.3.4"
   }
}
nbb クロージャのプログラマのための通常のワークフローである同じrepl駆動方法で開発することができます.すばらしいですね.
ラムダコードは比較的簡単ですが、私はまだいくつかの説明をしたいと思います.完全プロジェクトへのリンクは、ポストの最後にあります.
(ns handler
 (:require ["@aws-sdk/client-s3" :refer [S3Client]]
           ["@aws-sdk/s3-presigned-post" :refer [createPresignedPost]]
           [clojure.string :as s]
           [goog.string.format]
           [applied-science.js-interop :as j]
           [promesa.core :as p]))

(def s3 (S3Client. #js{:region "eu-west-1"}))

(def bucket-name-template "%s-docs-upload-bucket")

(defn handler [event _ctx]
     (p/let [{:keys [env folderName fileName]} (-> event
                                                   (j/get :pathParameters)
                                                   (j/lookup))
             key (str (s/replace folderName #"_" "/") "/" fileName)
             bucket-name (goog.string/format bucket-name-template env)
             response (createPresignedPost s3 (clj->js {:Bucket     bucket-name
                                                        :Key        key
                                                        :Expires    300
                                                        :Fields     {:key key}
                                                        :Conditions [["eq", "$key", key]
                                                                     ["content-length-range", 0, 10485760]
                                                                     ["starts-with", "$Content-Type", "text/"]]}))]
            (clj->js {:statusCode 200
                      :headers    {"Access-Control-Allow-Origin"  "*"
                                   "Access-Control-Allow-Headers" "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent,Access-Control-Allow-Origin",
                                   "Access-Control-Allow-Methods" "OPTIONS,GET"}
                      :body       (js/JSON.stringify response nil 2)})))

#js {:handler handler}

  • 慎重な読者は、なぜ:require 他の人がしないダブル引用符がありますか?この条約は1980年代から始まったshadow-clj 採用nbb 表すnpm 図書館
  • the p/let - 約束の連鎖のきちんとした方法:それぞれの式は約束表現として扱われ、順次実行されます
  • ラムダはenvironment , folder and filename 着信APIゲートウェイイベントからのパラメータ.これらは、どのバケットとアップロードのフォルダを理解するために必要ですが起こっている.j/lookup からのメソッドjs-interop ライブラリは、clojure破壊を使用することができます迅速かつ便利な方法です
  • ビジネスロジックS 3フォルダによって、ネストされるかもしれません.The folderName パラメタはネストしている自然を反映するためにアンダースコアを使用します
  • すべての必須パラメータが準備されるとき、署名ビットは遊びに入りますcreatePresignedPost メソッドはs3 クライアントインスタンスとoptions オブジェクト
  • clj->js Stinの上で正確にそれを言うことは、再帰的にCLJS値をJavaScriptに変えます;
  • 返されるresponse 我々が呼び出し元に渡す必要があるURLとフィールドから成ります.彼らは実際のアップロード用にそれを使用します
  • 再び使用clj->js からなるラムダ関数の応答をアセンブルするにはstatus , headers (簡単さのために)"Access-Control-Allow-Origin" が“すべてを許可する”が、それは正確な起源を指定することをお勧めします)とbody ;
  • ファイルを追加する必要があります.index.mjs - ノードに必要なES 6モジュール.JSアプリケーション.
    注意してくださいpromesa and js-interop ので、まっすぐにそれらを使用することができます内蔵ライブラリです!
    プロジェクト全体と配備命令はthis github repo .
    最近AWS発表Lambda Function URLs サポート.この機能を使用すると、httpsエンドポイントをAWSラムダに設定できます.これは、高度なAPIゲートウェイ機能を必要としない簡単なユースケースのための巨大な改善です.
    それから利益を得るために、我々はわずかに微調整を必要としますstack declaration とハンドラは、着信イベント構造が次のように変更されたためです.
    {
     "version": "2.0",
     "routeKey": "$default",
     "rawPath": "/dev/folder1/report1.csv",
     "rawQueryString": "",
     "headers": {
       "x-amzn-trace-id": "Root=1-4a40e828-b893-47b2-937c-19623c4f88e4",
       "x-forwarded-proto": "https",
       "host": "kafts7qpofkzbbvxbxxzavlv6i0aelqr.lambda-url.eu-west-1.on.aws",
       "x-forwarded-port": "443",
       "x-forwarded-for": "aeaf:c432:4e41:50ee:060d:fc8d:5d42:df65",
       "accept": "*/*",
       "user-agent": "curl/7.64.1"
     },
     "requestContext": {
       "routeKey": "$default",
       "stage": "$default",
       "time": "11/Apr/2022:07:54:29 +0000",
       "domainPrefix": "kafts7qpofkzbbvxbxxzavlv6i0aelqr",
       "requestId": "cd14fcd8-ff00-4fd9-a13a-3bc772f038ea",
       "domainName": "kafts7qpofkzbbvxbxxzavlv6i0aelqr.lambda-url.eu-west-1.on.aws",
       "http": {
         "method": "GET",
         "path": "/dev/folder1/report1.csv",
         "protocol": "HTTP/1.1",
         "sourceIp": "aeaf:c432:4e41:50ee:060d:fc8d:5d42:df65",
         "userAgent": "curl/7.64.1"
       },
       "accountId": "anonymous",
       "apiId": "kafts7qpofkzbbvxbxxzavlv6i0aelqr",
       "timeEpoch": 1649663669499
     },
     "isBase64Encoded": false
    }
    
    このようにしてenvironment , folder and filename 現在
    (defn handler [event _ctx]
         (p/let [[env folderName fileName] (-> event
                                               (j/get-in [:requestContext :http :path])
                                               (s/split #"/")
                                               (rest))
    ...
    
    ハンドラの実装の残りは同じままでした.
    読書ありがとう🙏, あなたがそれが役に立つと思います.
    ご質問、ご提案とフィードバックがある場合は私に知らせてください.