cURL คืออะไร? มาลองหัดใช้กันดีกว่า

cURL Jun 7, 2023

วันนี้มาแนะนำการใช้งาน cURL นะครับ cURL คือ Client URL เป็น Command Line ที่เอาไว้สำหรับรับส่งข้อมูล ระหว่าง Client และ Server

ปกติเวลาเราทำการทดสอบ API เพื่อ request GET PUT POST ต่างๆ ส่วนใหญ่คงจะใช้ Tool เช่น Postman กันแน่ๆ แต่วันนี้ลองมาใช้ cURL เบื้องต้นกันดีกว่าครับ รู้ไว้ไม่เสียหาย และบาง API Document ก็จะมีตัวอย่าง cURL มาให้ เราจะได้เข้าใจว่า มันเรียกยังไง เช่น

  • ส่งค่า payload
  • กำหนด Content Type ปรับแต่ง headers
  • แก้ user agent

วันนี้จะมาพูดถึงเฉพาะ cURL ว่ามันคืออะไร ใช้งานยังไง ซึ่งในตัวอย่างบทความนี้ส่วนใหญ่จะใช้ Github API มาเป็นตัวอย่างครับ เพราะมันมี API ค่อนข้างที่จะครบเลยทีเดียว

TLDR;


$ curl https://api.github.com

$ curl -i https://api.github.com

# use `--user` (`-u`) for basic http authentication
$ curl --user "user:password" https://api.github.com

# only username without the colon will prompted for input password.
$ curl --user "user" https://api.github.com

$ curl -H 'Content-Type: application/json' https://api.github.com

# HTTP Post use `--request` (`-X`) กับ `--data` (`-d`)
$ curl -H 'Content-Type: application/json' -d '{}' -X POST https://api.github.com

$ curl -H "Accept: application/json" \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer eJ0.....' \
-d '{"username": "chai"}' \
-X POST \
https://api.github.com

Basic

ก่อนใช้งาน cURL เราต้องทำการติดตั้งมันซะก่อน หากไม่มีสามารถดาวน์โหลดได้จากนี้ Download cURL

บน Mac OS X สามารถติดตั้งผ่าน homebrew ได้ง่ายๆ (ปกติน่าจะมีติดตั้งมาแล้ว แต่ถ้ารัน homebrew ก็เป็นเหมือนกับการ upgrade version)

brew install curl

บน Linux ก็เช่นกัน

sudo apt-get install curl

ทดสอบว่ามี cURL บนเครื่องจริงหรือไม่ โดยการเปิด Terminal แล้วพิมพ์

curl --version

# result
curl 7.88.1 (x86_64-apple-darwin22.0) libcurl/7.88.1 (SecureTransport) LibreSSL/3.3.6 zlib/1.2.11 nghttp2/1.51.0
Release-Date: 2023-02-20

การใช้งาน cURL นั้นง่ายมากๆ แล้วพิพม์คำสั่งตาม syntax ของมันเลย

curl <OPTION> <URL>

ตัวอย่าง เช่น การดึงข้อมูลจากเว็บไซต์ https://google.com

curl https://google.com

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://www.google.com/">here</A>.
</BODY></HTML>

จะเห็นว่าข้อมูลนั้นขึ้นว่า "The document has moved" หมายความว่า url ที่เราทำการขอดึงข้อมูลนั้นมีการ redirect ไปที่อื่น การที่เราจะให้มัน following redirect ด้วย ทำได้โดยการใส่ option -L ให้มัน ดังนี้

curl -L https://google.com

<!doctype html><html>
...
... // code HTML
... // ยาวมากๆ
</html>

ลองดึงข้อมูล Github API

curl https://api.github.com


{
  "current_user_url": "https://api.github.com/user",
  "current_user_authorizations_html_url": "https://github.com/settings/connections/applications{/client_id}",
  "authorizations_url": "https://api.github.com/authorizations",
  "code_search_url": "https://api.github.com/search/code?q={query}{&page,per_page,sort,order}",
  "commit_search_url": "https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}",
  "emails_url": "https://api.github.com/user/emails",
  "emojis_url": "https://api.github.com/emojis",
  "events_url": "https://api.github.com/events",
  "feeds_url": "https://api.github.com/feeds",
  "followers_url": "https://api.github.com/user/followers",
  "following_url": "https://api.github.com/user/following{/target}",
  "gists_url": "https://api.github.com/gists{/gist_id}",
  "hub_url": "https://api.github.com/hub",
  "issue_search_url": "https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}",
  "issues_url": "https://api.github.com/issues",
  "keys_url": "https://api.github.com/user/keys",
  "label_search_url": "https://api.github.com/search/labels?q={query}&repository_id={repository_id}{&page,per_page}",
  "notifications_url": "https://api.github.com/notifications",
  "organization_url": "https://api.github.com/orgs/{org}",
  "organization_repositories_url": "https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}",
  "organization_teams_url": "https://api.github.com/orgs/{org}/teams",
  "public_gists_url": "https://api.github.com/gists/public",
  "rate_limit_url": "https://api.github.com/rate_limit",
  "repository_url": "https://api.github.com/repos/{owner}/{repo}",
  "repository_search_url": "https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}",
  "current_user_repositories_url": "https://api.github.com/user/repos{?type,page,per_page,sort}",
  "starred_url": "https://api.github.com/user/starred{/owner}{/repo}",
  "starred_gists_url": "https://api.github.com/gists/starred",
  "topic_search_url": "https://api.github.com/search/topics?q={query}{&page,per_page}",
  "user_url": "https://api.github.com/users/{user}",
  "user_organizations_url": "https://api.github.com/user/orgs",
  "user_repositories_url": "https://api.github.com/users/{user}/repos{?type,page,per_page,sort}",
  "user_search_url": "https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"
}

หากอยากดูเฉพาะส่วน Header ละ? ก็แค่ใส่ option --head หรือ -I แบบนี้

curl -I https://api.github.com

HTTP/2 200
server: GitHub.com
date: Wed, 07 Jun 2023 14:00:04 GMT
content-type: application/json; charset=utf-8
cache-control: public, max-age=60, s-maxage=60
...

Option อื่นๆ ก็จะมี

  • --verbose (-v) เพื่อเอาไว้ debug เพราะมันจะแสดงข้อมูลทุกๆ action
  • --include (-i) เพื่อใส่ Header แนบมาด้วยกับ response body (ต่างจาก --head ที่เอาเฉพาะ header ไม่เอา body)

Downloading files (-o)

เราสามารถใช้ cURL เพื่อทำการดาวน์โหลดไฟล์ได้ เช่น ตัวอย่าง จะโหลดไฟล์ จากเว็บ bigbuckbunny โดยเลือกไฟล์ BigBuckBunny_320x180.mp4 เราสามารถใช้ option -O เพื่อดาวน์โหลดไฟล์ได้ :

$ curl -O http://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                               Dload  Upload   Total   Spent    Left  Speed
0 61.6M    0  510k    0     0    98k      0  0:10:38  0:00:05  0:10:33  103k

เราสามารถใช้ option อื่นๆร่วมกันได้ เช่น

  • -o 'filename' : เพื่อทำการเปลี่ยนชื่อไฟล์ output ได้
  • -C - : เพื่อให้มันทำการ resume ดาวน์โหลดที่ค้างไว้
  • -# : เปลี่ยนให้เป็นในรูป Progress Bar

ลองใช้ option เพิ่มเข้ามาจะเป็นแบบนี้

$ curl -# -C - -o 'bunny.mp4' http://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4

########################################                                  56.9%

Download/Upload FTP

ตัวอย่างการ Download ข้อมูลจาก FTP ทำเหมือนกับการดาวน์โหลดไฟล์ปกติเลย เพียงแค่เปลี่ยนโปรโตคอลจาก http/https เป็น ftp พร้อมกับใส่ user และ password แนบไปด้วย ดังนี้

$ curl ftp://myserver.com/path/to/my/folder/super_file.txt --user user:password

ส่วนวิธีการอัพโหลดข้อมูลผ่าน FTP ก็ทำเหมือนกัน เพียงแค่ใส่ option -T และระบุชื่อไฟล์ดังนี้

$ curl -T super_secret.zip ftp://myserver.com/path/to/my/folder --user user:password

HTTP Basic Auth

ตัวอย่างการใช้งานเพื่อ Access เข้า Web ที่มี Basic Authentication ทำได้โดยการใส่ option --user หรือ -u แล้วตามด้วย username:password (username ตามด้วย colon(:) และ password) เช่น

$ curl -u "user:pass" [URL]

ซึ่งเมื่อเราส่ง -u "user:pass" ตัว cURL จะ build ให้เป็น Header ชื่อ Authorization และเข้ารหัสเราด้วย base64encoding ซึ่งจากด้านบน cURL จะแปลงได้เป็นแบบนี้

$ curl -H 'Authorization: Basic dXNlcjpwYXNz' [URL]

Headers

ต่อมาการใส่ custom header ให้กับ HTTP Header ได้ เช่น ให้ Accept เฉพาะ JSON หรือ Content-Type ต้องเป็น JSON เท่านั้น หรือกรณีใส่ authToken, accessToken ผ่าน custom header สามารถทำได้ผ่าน option --header หรือ -H ตัวอย่าง:

$ curl -H "x-access-token: mytoken" [URL]

$ curl -H "Content-Type: application/json" -H "Accept: application/json" [URL]

POST

มาถึงส่วนของ HTTP POST กันบ้างส่วนนี้จะมีปัญหากันเยอะ เนื่องจากว่า วิธีการส่งข้อมูล นั้นสามารถส่งได้หลายแบบ ไม่ว่าจะเป็น

  • x-xxx-form-urlencoded
  • form-data
  • JSON

ซึ่งส่วนที่เราจะรู้ว่า body payload ที่จะส่งไปแต่ละชนิดเป็นอะไร ก็ดูจาก Content-Type ในส่วน HTTP Header นั่นเอง

ส่ง payload แบบ x-xxx-form-urlencoded

การส่ง ข้อมูล body payload ทำด้วยด้วย option --data หรือ -d พร้อมกับข้อมูลแบบ key=value&key2=value ดังนี้

$ curl -X POST -d "name=Chai&password=xxxx" [URL]

ซึ่งด้านบนเป็นการส่ง body payload ชนิด Content-Type: application/x-www-form-urlencoded

ส่ง payload แบบ form-data

ต่อมาการส่ง body payload แบบ upload file จะใช้ option -F และตั้งค่า Header เป็นแบบ Content-Type: multipart/form-data

สมมติไฟล์ HTML เราเป็นแบบนี้

<form method="POST" enctype="multipart/form-data" action="...">
  <input type="file" name="file" />
  <input type="submit" name="press" value="OK" />
</form>

การส่ง File Upload แนบไปกับ POST สามารถทำได้แบบนี้

$ curl -X POST -H "Content-Type: multipart/form-data -F "file=@filename.png" -F "press=ok" [URL]

ส่ง payload แบบ JSON

การส่ง body payload แบบ JSON ทำได้ด้วยการ add Content-Type: application/json แบบนี้

$ curl -X POST -H "Content-Type: application/json" -d '{"name": "Chai"}' [URL]

หรือถ้าหากเรามีไฟล์ data.json

{
  "firstname": "Chai",
  "lastname": "Phonbopit",
  "website": "https://devahoy.com"
}

เราก็สามารถส่งข้อมูลโดยอ้างอิงข้อมูลในไฟล์ JSON ก็ได้ โดยใช้เครื่องหมาย @filename.json ดังเช่น

$ curl -X POST -H "Content-Type: application/json" -d @data.json [URL]

สุดท้าย หากคำสั่ง cURL มันยาวเกิน เราสามารถขึ้นบรรทัดใหม่ได้ด้วย \

$ curl -X POST \
-H "Content-Type: application/json" \
-d @data.json [URL]

Github API Example

มาลองใช้ cURL ยิง Github API กันดูบ้างดีกว่า เริ่มแรกต้องรู้ว่า Github API มี API ไหนที่ยิงได้แบบไม่ต้องผ่าน Authentication และอันไหนต้อง required

สำหรับ API ที่ไม่ต้อง required authentication ก็พวก public data ต่างๆ เช่นข้อมูล user

$ curl https://api.github.com/users/phonbopit

Authentication

ส่วนที่ต้อง Authentication ก่อน ซึ่งวิธี Authentication ก็มีหลายแบบ เช่น

  • Basic Authentication
curl -u "username" https://api.github.com

ซึ่งหากเราติด 2 Factor Authentication ก็ต้องส่ง X-Github-OTP: number แนบติด Header ไปด้วย

  • OAuth2 Token ส่งได้ทั้งแบบ header และ queryString
curl -H "Authorization: token OAUTH-TOKEN" https://api.github.com
curl https://api.github.com/?access_token=OAUTH-TOKEN

ซึ่งวิธีการที่เราจะได้ OAuth2 มานั้นมีหลายวิธี แต่เอาวิธีที่ทำได้ง่ายๆ ด้วยการ generate ผ่านหน้าเว็บเลย Generate new token

ทำการเลือก scope ที่ต้องการ เช่น repo, delete_repo เป็นต้น

ต่อมาลองเรียก เพื่อดู repositories ทั้งหมดของเรา

$ curl https://api.github.com/user/repos

{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

จะได้ HTTP/1.1 401 Unauthorized ไม่ผ่านการ Authentication เนื่องจากว่าส่วนนี้จำเป็นต้องแนบ Token หรือระบุ Basic Auth ไปด้วย วิธีการก็คือใช้ token ที่เรา generate จากด้านบน ส่งไปเป็น queryString แบบนี้

$ curl https://api.github.com/user/repos?access_token=your_token

หรือจะส่งเป็น Header ก็ได้แบบนี้

$ curl https://api.github.com/user/repos -H "Authorization: token your_token"

Create repo

ลองใช้ cURL ทำการสร้าง repository เราดูบ้าง ซึ่ง API ที่ทาง Github ให้ใช้ก็คือ

  • POST https://api.github.com/user/repos

โดยข้อมูลที่ต้องส่งไปก็มีพวก name, description, homepage, private อื่นๆ ซึ่งตัวอย่าง JSON ตามข้างล่างนี ชื่อ create_repo.json

{
  "name": "Hello-World",
  "description": "This is repo create from cURL",
  "homepage": "https://devahoy.com/blog/2016/11/getting-started-with-curl/",
  "private": false,
  "has_issues": true,
  "has_wiki": true,
  "has_downloads": true,
  "auto_init": true
}

ต่อมาสร้าง repo ผ่าน cURL

$ curl -u username -X POST -d @create_repo.json https://api.github.com/user/repos

แบบใช้ token

$ curl -X POST -H "Authorization: token your_token" -d @create_repo.json https://api.github.com/user/repos

ทีนี้ repo เราก็ถูกสร้างเรียบร้อยแล้ว


HTTP/1.1 201 Created

{
  "id": 73729178,
  "name": "Hello-World",
  "full_name": "Phonbopit/Hello-World",
  "owner": {
  },
  "html_url": "https://github.com/Phonbopit/Hello-World",
  "description": "This is repo create from cURL",
  "fork": false,
  "url": "https://api.github.com/repos/Phonbopit/Hello-World",
}

เรียบร้อย ¯\_ (ツ) _/¯

HTTPie

รูปจากเว็บ https://httpie.io/

แนะนำ HTTPie สำหรับคนที่ไม่อยากใช้ cURL ก็มีอีก Tool ที่ทำหน้าที่แบบเดียวกับ cURL เลยแต่ว่ามันดูง่ายกว่า มีสี highlight อ่านง่าย รวมถึงวิธีใช้งานก็ง่ายกว่า cURL

วิธีการติดตั้งบน Mac OS X ผ่าน Homebrew

brew install httpie

บน Linux

sudo apt-get install httpie

ติดตั้งผ่าน python pip

pip install --upgrade httpie

วิธีใช้งานก็ง่ายๆ แค่

$ http [URL]

เช่น

$ http https://google.com

HTTP/1.1 302 Found
Alt-Svc: quic=":443"; ma=2592000; v="36,35,34"
Cache-Control: private
Content-Length: 262
Content-Type: text/html; charset=UTF-8
Date: Mon, 14 Nov 2016 17:06:08 GMT
Location: https://www.google.co.th/?gws_rd=cr&ei=x
P3P: CP="This is not a P3P policy! See https://www.google.com/support/accounts/answer/151657?hl=en for more info."
Server: gws
Set-Cookie: NID=90=x; expires=Tue, 16-May-2017 17:06:08 GMT; path=/; domain=.google.com; HttpOnly
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="https://www.google.co.th/?gws_rd=cr&amp;ei=x">here</A>.
</BODY></HTML>

จุดเด่นของ HTTPie คือ

  • Content-Type และ Accept เป็น application/json โดย default
  • แสดง Header มาเป็น default
  • แสดงสี highlight และจัด format output ให้ง่ายต่อการอ่าน

สำหรับ HTTPie ยังมี Features อื่นๆที่น่าสนใจอีกเยอะ และบางทีก็สะดวกกว่าใช้ cURL ก็ลองไปอ่านเพิ่มเติมดูได้ครับ

ปัจจุบัน Httpie นอกจาก CLI แล้ว ก็มีเวอร์ชั่นที่เป็นเว็บเลย คล้ายๆ Postman ลองไปดูได้ครับ

HTTPie for Web — API testing client
Start testing REST, GraphQL, and HTTP APIs from the browser in 1s. Free, no account needed.

ไหนๆ ก็พูดถึง Postman แล้ว เผื่อใครที่ผ่านมาอ่าน อยากได้โปรแกรมคล้ายๆ Postman ก็ยังมีพวก Insomnia, Hoppscotch หรือ VS Code Extensions อย่าง Thunder Client ลองไปใช้กันดูนะครับ

The Collaborative API Development Platform
Leading Open Source API Development Platform for HTTP, REST, GraphQL, gRPC, SOAP, and WebSockets
Hoppscotch • Open source API development ecosystem
Helps you create requests faster, saving precious time on development.
Thunder Client - Rest API Client Extension for VS Code
Thunder Client is a hand-crafted lightweight Rest API Client extension for Visual Studio Code

References

GitHub - bagder/everything-curl: The book documenting the curl project, the curl tool, libcurl and more. Simply put: everything curl.
The book documenting the curl project, the curl tool, libcurl and more. Simply put: everything curl. - GitHub - bagder/everything-curl: The book documenting the curl project, the curl tool, libcurl…
Conquering the Command Line
Learn to master and conquer the most valuable and useful command line tools for Unix and Linux based systems. In this book you will find not only the most useful command line tools you need to know, but also the most helpful options and flags for those tools. Conquering the Command Line isn’t just…
HTTPie – API testing client that flows with you
Making APIs simple and intuitive for those building the tools of our time.

Tags

Chai Phonbopit

เป็น Web Dev ทำงานมา 10 ปีหน่อยๆ ด้วยภาษา JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจ Web3, Crypto และ Blockchain เขียนบล็อกที่ https://devahoy.com