งานที่ทำต้องการ upload file ขึ้น service ที่ compatible กับ AWS S3 เลยเลือกใช้ library ex_aws ช่วยในการเรียกใช้ S3 API ในการอัพโหลดไฟล์ ซึ่งต้องใช้งานร่วมกับ library ex_aws_s3
สิ่งที่ทำให้ต้องมาเขียนโพสต์นี้ก็เพราะว่า document ของ library นี้มันไม่เคลียร์ว่า response ที่มันตอบกลับมานั้นจะอยู่ในรูปแบบไหนกันแน่ เช่นต้องการอัพโหลดไฟล์ในตัวอย่างเขียนไว้แค่นี้
"path/to/big/file"
|> ExAws.S3.Upload.stream_file
|> ExAws.S3.upload("my-bucket", "path/on/s3")
|> ExAws.request #=> {:ok, :done}
กับ get_object เขียนไว้แค่นี้
ExAws.S3.get_object("my-bucket", "image.png") |> ExAws.request
แต่จริงๆแล้วตอน upload จะได้ reponse แบบนี้
{:ok,
%{
body: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CompleteMultipartUploadResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Location>http://localhost:9000/my-bucket/mix.exs</Location><Bucket>my-bucket</Bucket><Key>mix.exs</Key><ETag>"5ca9425fced3f0bc1670a8f1fccbe29d-1"</ETag></CompleteMultipartUploadResult>",
headers: [
{"Accept-Ranges", "bytes"},
{"Cache-Control", "no-cache"},
{"Content-Length", "311"},
{"Content-Security-Policy", "block-all-mixed-content"},
{"Content-Type", "application/xml"},
{"ETag", "\"5ca9425fced3f0bc1670a8f1fccbe29d-1\""},
{"Server", "MinIO"},
{"Vary", "Origin"},
{"X-Accel-Buffering", "no"},
{"X-Amz-Request-Id", "166840A0DBB74310"},
{"X-Xss-Protection", "1; mode=block"},
{"Date", "Mon, 01 Mar 2021 15:12:06 GMT"}
],
status_code: 200
}}
แต่จริงๆแล้วตอน get_object จะได้ reponse แบบนี้
{:ok,
%{
body: "defmodule S3Example.MixProject do\n use Mix.Project\n\n def project do\n [\n app: :s3_example,\n version: \"0.1.0\",\n elixir: \"~> 1.11\",\n start_permanent: Mix.env() == :prod,\n deps: deps()\n ]\n end\n\n # Run \"mix help compile.app\" to learn about applications.\n def application do\n [\n extra_applications: [:logger]\n ]\n end\n\n # Run \"mix help deps\" to learn about dependencies.\n defp deps do\n [\n {:ex_aws, \"~> 2.1\"},\n {:ex_aws_s3, \"~> 2.1\"},\n {:hackney, \"~> 1.9\"},\n {:jason, \"~> 1.2\"},\n {:sweet_xml, \"~> 0.6\"}\n # {:dep_from_hexpm, \"~> 0.3.0\"},\n # {:dep_from_git, git: \"https://github.com/elixir-lang/my_dep.git\", tag: \"0.1.0\"}\n ]\n end\nend\n",
headers: [
{"Accept-Ranges", "bytes"},
{"Content-Length", "717"},
{"Content-Security-Policy", "block-all-mixed-content"},
{"Content-Type", "application/octet-stream"},
{"ETag", "\"5ca9425fced3f0bc1670a8f1fccbe29d-1\""},
{"Last-Modified", "Mon, 01 Mar 2021 15:12:06 GMT"},
{"Server", "MinIO"},
{"Vary", "Origin"},
{"X-Amz-Request-Id", "166840A6DA0B6B08"},
{"X-Xss-Protection", "1; mode=block"},
{"Date", "Mon, 01 Mar 2021 15:12:31 GMT"}
],
status_code: 200
}}
จะเห็นว่าก็เป็น pattern {:ok, %{body: , headers: [], status_code: }}
ด้วยความสงสัยเลยไปแงะโค้ดดูพบว่า concept ของมันคือให้สร้าง Operation struct เพื่อเก็บขอมูลของ Request แล้วให้ implement protocol ExAws.Operation ที่มี function perform
กับ stream!
เสร็จแล้วเมื่อเราส่งต่อค่าของ operation ไปให้ฟังก์ชัน ExAws.request
มันจะเรียก perform
ให้นั่นเอง ซึ่งพอไปดูโค้ดของ ExAws.request
จะเห็นโค้ดแบบนี้
ExAws.Operation.perform(op, ExAws.Config.new(op.service, config_overrides))
สรุปว่า จริงๆแล้วเวลาเห็นโค้ดแบบด้านบน เราต้องดูว่ามันสร้างค่าของ Operation struct ตัวไหนก่อนจะเรียกไปหา ExAws.request
แล้วก็ไปดู perform
ของมันว่าทำอะไรแล้วได้อะไรกลับออกมา เช่น ExAws.S3.upload
นั้นได้ operation ExAws.S3.Upload
ก็ต้องไปไล่ๆหาในฟังก์ชัน perform
ของ operation Upload นั่นเอง
จะเห็นว่าตัว document ของ ex_aws
กับ ex_aws_s3
ยังปรับปรุงได้อีกเพื่อให้คนที่ต้องใช้งานเข้าใจได้ง่ายขึ้นว่าจะได้ response แบบไหนออกมา เดี๋ยวว่างๆวันหยุดจะลองไปช่วย contribute ดู
ขอฝาก Buy Me a Coffee
สำหรับท่านใดที่อ่านแล้วชอบโพสต์ต่างๆของผมที่นี่ ต้องการสนับสนุนค่ากาแฟเล็กๆน้อยๆ สามารถสนับสนุนผมได้ผ่านทาง Buy Me a Coffee คลิ๊กที่รูปด้านล่างนี้ได้เลยครับ
ส่วนท่านใดไม่สะดวกใช้บัตรเครดิต หรือ Paypal สามารถสนับสนุนผมได้ผ่านทาง PromptPay โดยดู QR Code ได้จากโพสต์ที่พินเอาไว้ได้ที่ Page DevDose ครับ https://web.facebook.com/devdoseth
ขอบคุณครับ 🙏
Top comments (0)