<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pallat Anchaleechamaikorn</title>
    <description>The latest articles on DEV Community by Pallat Anchaleechamaikorn (@pallat).</description>
    <link>https://dev.to/pallat</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F283935%2Fe5a21336-efca-4247-9830-ea29e96e23fd.jpeg</url>
      <title>DEV Community: Pallat Anchaleechamaikorn</title>
      <link>https://dev.to/pallat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pallat"/>
    <language>en</language>
    <item>
      <title>คุยกันเรื่อง Writing Better Go: Lessons from 10 Code Reviews</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Fri, 09 Jan 2026 08:37:20 +0000</pubDate>
      <link>https://dev.to/pallat/khuykaneruueng-writing-better-go-lessons-from-10-code-reviews-2jgf</link>
      <guid>https://dev.to/pallat/khuykaneruueng-writing-better-go-lessons-from-10-code-reviews-2jgf</guid>
      <description>&lt;p&gt;ใน reddit ของ r/golang มีการนำเอา &lt;a href="https://speakerdeck.com/konradreiche/writing-better-go-lessons-from-10-code-reviews" rel="noopener noreferrer"&gt;Writing Better Go: Lessons from 10 Code Reviews&lt;/a&gt; ของ Konrad Reiche มาสรุปโดย Asleep-Actuary-4428 &lt;a href="https://www.reddit.com/r/golang/comments/1oc5is8/writing_better_go_lessons_from_10_code_reviews/" rel="noopener noreferrer"&gt;ที่นี่&lt;/a&gt; ซึ่งสรุปได้เข้าใจง่าย เลยอยากเอามาเล่าต่อ&lt;br&gt;
สามารถเปิดดู slide ต้นทางไปพร้อมๆกับการอธิบายแต่ละข้อได้เลย&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Handle Errors

&lt;ul&gt;
&lt;li&gt;อย่าทำเป็นเมิน error ไปแบบเงียบๆ (เช่นเอา _ ไปรับค่า error)&lt;/li&gt;
&lt;li&gt;อย่าคิดว่า error นี้รับได้เช่น if err != nil { return nil }&lt;/li&gt;
&lt;li&gt;ถ้าเจอ error ต้องตรวจสอบก่อนอย่างอื่นและจัดการมันเลย เช่น log ตอนนั้นเลย แล้ว error นั้นก็ถือซะว่าถูกจัดการไปแล้ว ก็ไม่ต้องส่งต่อให้คนอื่น&lt;/li&gt;
&lt;li&gt;อย่าโวยซ้ำ ถ้า log ไปรอบนึงแล้วยัง return ต่อให้คนอื่นไปโวยต่อ เขาก็เอาไป log อีก&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;bad&lt;/th&gt;
&lt;th&gt;good&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;if err != nil {&lt;br&gt;    slog.Error(err)&lt;br&gt;     return err &lt;br&gt; }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;if err != nil {&lt;br&gt;    slog.Error(err)&lt;br&gt;     return nil &lt;br&gt; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;ลดภาระให้ฝั่งที่เรียกใช้

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;return result, nil&lt;/em&gt; แบบนี้&lt;strong&gt;ดี&lt;/strong&gt;เพราะคืนผลลัพธ์และไม่มี error ให้สับสน&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;return nil, err&lt;/em&gt; แบบนี้ก็&lt;strong&gt;ดี&lt;/strong&gt;เพราะมี error ให้จัดการในขณะที่ไม่มีผลลัพธ์&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;return nil, nil&lt;/em&gt; แบบนี้&lt;strong&gt;แย่&lt;/strong&gt; ถึงแม่ว่าจะไม่มี error แต่การไม่มีผลลัพธ์ส่งออกไป มันทำให้คนเรียกต้องไปตีความต่อ&lt;/li&gt;
&lt;li&gt;_return result, err _อันนี้ก็&lt;strong&gt;แย่&lt;/strong&gt; ไม่รู้ว่ามันจะต้อง error หรือว่าใช้ได้กันแน่ มันต้องไปตีความต่ออีกว่าจะเชื่อค่าไหน&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;ใส่ interface เร็วไป&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;การใช้ interface แบบผิดๆเป็นภาพที่เห็นบ่อย เพราะมักจะเห็นการสร้าง interface ก่อนเลย (ซึ่งเป็นท่าที่อาจจะเอามาจากบางภาษาเช่น จาวา) หรือทำเพื่อให้ test เช่นทำเพื่อให้ mock ใน test เนื่องจากพอมันมาเร็วไป มันจะทำให้โค้ดอ่านยากขึ้นทันที&lt;/li&gt;
&lt;li&gt;อย่าเริ่มด้วย interface&lt;/li&gt;
&lt;li&gt;ให้ใช่ท่า &lt;strong&gt;accept interfaces, return concrete types&lt;/strong&gt; หรือก็คือ สื่อสารกันผ่าน interface แต่ตอนคืนให้คืนด้วย type จริง&lt;/li&gt;
&lt;li&gt;ทุกอย่างให้เริ่มจากการใช้ type จริงไปก่อน จนกว่าโค้ดมันจะพาเราไปถึงจุดที่จะต้องใช้ interface จริงๆแล้วค่อยใช้&lt;/li&gt;
&lt;li&gt;Litmus Test: ถ้าเราไม่ใช้ interface แล้ว test ได้ ก็ไม่เห็นต้องใช้เลยนี่นา&lt;/li&gt;
&lt;li&gt;อย่าสร้าง interface เพียงเพื่อให้เทสได้เพียงอย่างเดียว อยากให้ลองเทสโดยไม่ต้องมีดูก่อน&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mutexes Before Channels&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เมื่อเริ่มใช้ channel โค้ดจะเริ่มซับซ้อนมาก ซึ่งมันสร้างโอกาสเสี่ยงที่จะเกิด panic ง่ายขึ้น เช่นเมื่อไปเผลอ close channel หรือส่งของเข้า channel ที่ closed ไปแล้ว หรืออาจเกิด deadlocks&lt;/li&gt;
&lt;li&gt;เริ่มด้วยวิธีง่ายๆ ไปทีละขั้น&lt;/li&gt;
&lt;li&gt;เริ่มจาก sync ก่อน อย่าเพิ่งรีบไป async&lt;/li&gt;
&lt;li&gt;ใส่ goroutine เมื่อ profiling แสดงให้เห็นคอขวดจริงๆก่อน&lt;/li&gt;
&lt;li&gt;ใช้ &lt;code&gt;sync.Mutex&lt;/code&gt; และ &lt;code&gt;sync.WaitGroup&lt;/code&gt; จัดการกับ shared state ดูก่อน&lt;/li&gt;
&lt;li&gt;Channel จะฉายแสงเมื่อต้องเล่นกับการจัดการที่มีความซับซ้อนจริงๆ ไม่ใช่เอามาใช้กับเรื่องเบบี๋ธรรมดา ไม่คุ้ม&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Declare ทุกอย่างให้ใกล้กับจุดที่จะใช้ให้มากที่สุด&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;นี่เป็นท่ามาตรฐานสำหรับการประกาศ constants, variables, functions and types&lt;/li&gt;
&lt;li&gt;ประกาศของเหล่านี้ไว้ในไฟล์ที่มีการใช้งานมันจริงๆ และ Export (ชื่อขึ้นด้วย CApital Letter) เมื่อมีความต้องการใช้งานจากนอก package จริงๆก่อน&lt;/li&gt;
&lt;li&gt;ในฟังก์ชั่นก็เช่นกัน ประกาศตัวแปรให้ใกล้จุดที่จะถูกใช้ให้มากที่สุด&lt;/li&gt;
&lt;li&gt;จำกันขอบเขตมันให้เล็กที่สุดเช่นทำ 1 statement ใน if&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;อย่าให้เกิด runtime panics&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ท่าง่ายสุดก็คือให้ตรวจสอบ input ที่เข้ามาจากภายนอกก่อนเอาไปใช้&lt;/li&gt;
&lt;li&gt;อย่าใช้ &lt;code&gt;if x == nil&lt;/code&gt; ก็ในเมื่อคุณเป็นคนควบคุมการไหลของข้อมูลมาแล้ว ก็ให้เชื่อในการจัดการ error ในแต่ละจุดไปเลย&lt;/li&gt;
&lt;li&gt;ถ้าจะ dreference ค่า pointer เช่น &lt;code&gt;*p = 10&lt;/code&gt; จะต้อง check nil ก่อนเสมอ&lt;/li&gt;
&lt;li&gt;และการใช้ pointer ให้ปลอดภัยที่สุดก็คือ อย่าใช้มัน หมายถึงพยายามออกแบบให้ไม่ต้องใช้ pointer ให้ได้ก่อน&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ใช้เว้นวรรคให้น้อย&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ก็คืออย่าห่อลอจิกหลายๆชั้นเช่น if ซ้อน if ซ้อน for&lt;/li&gt;
&lt;li&gt;อยากชวนให้ใช้ท่า Return Early, Flatter Structure ด้วยการจัดการ error ก่อน แล้วค่อยไปทำอย่างอื่น หรือกำจัดเงื่อนไขที่จะไม่ทำต่อก่อนเลย&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;หลีกเลี่ยงการตั้งชื่อไฟล์และแพ็กเก็จด้วยชื่อคลุมเครือ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เช่น util.go, misc.go, constants.go หรือ interfaces/interfaces.go&lt;/li&gt;
&lt;li&gt;อยากให้สื่อความว่ามันมีไว้ทำไม มากกว่าจะบอกว่ามันอยู่ลำดับชั้นไหน&lt;/li&gt;
&lt;li&gt;โค้ดจะอ่านง่ายเมื่อมันอยู่ใกล้ๆกันกับอะไรที่มันเกี่ยวข้องกัน ไม่ใช่แยกกันไปคนละทิศ&lt;/li&gt;
&lt;li&gt;ตั้งชื่อ package ตามโดเมน หรืองานของมัน&lt;/li&gt;
&lt;li&gt;จัดกลุ่มตามความหมาย ไม่ใช่ตาม type เช่น ไปจัดกลุ่มของ controller แบบนี้ไม่เอา&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;เรียงลำดับ declarations ตามลำดับความสำคัญ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ใน Go มันช่วยให้อ่านง่ายขึ้น&lt;/li&gt;
&lt;li&gt;โค้ดไหนสำคัญ เอาขึ้นด้านบนเลย&lt;/li&gt;
&lt;li&gt;เช่นพวกที่ต้อง exported หรือ ฟังก์ชั่นที่เป็น API-facing เอาขึ้นข้างบนก่อน&lt;/li&gt;
&lt;li&gt;ตามด้วยพวก helper function พวกนี้มันจะช่วยอธิบายของข้างบน&lt;/li&gt;
&lt;li&gt;เรียงตามความสำคัญ ไม่ใช่ตามความสัมพันธ์ เพื่อให้คนที่มาอ่าน ลำดับความสำคัญจากมากลงมา&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ตั้งชื่อให้ดี&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;หลีกเลี่ยงการเอา type มาเติมท้ายชื่อ (เช่น userMap, idStr, injectFn) ชื่อตัวแปรควรบอกว่ามันเก็บอะไร ไม่ใช่บอกว่ามัน type อะไร&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ความยาวของชื่อควรสอดคล้องกับ scope เช่นถ้าตั้งชื่อด้วยอักษรเดียว scope มันควรจะสั้น ไม่ใช่ประกาศ global ด้วยชื่อตัวเดียว อายเค้านะ&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ทำ Document เพื่อตอบคำถามว่ามีไว้ทำไม ไม่ใช่แค่ว่ามันทำอะไรได้&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ให้เหตุผลว่ามันมีไว้ทำไม ทำไมต้องใช้มัน&lt;/li&gt;
&lt;li&gt;เวลาเขียน comment ควรสื่อถึงจุดประสงค์หรือประโยชน์ ไม่งั้นก็เหมือนเขียนโค้ดซ้ำธรรมดา&lt;/li&gt;
&lt;li&gt;Document คือเจตนา ไม่ใช่วิธีการ&lt;/li&gt;
&lt;li&gt;คนที่มาอ่านภายหลัง ควรที่จะเข้าใจแรงจูงใจที่คุณทำสิ่งนี้ออกมา เพราะเขาอ่านโค้ดก็รู้ว่ามันทำอะไร แต่ไม่รู้ว่าทำไมต้องทำแบบนี้&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>codequality</category>
      <category>go</category>
      <category>learning</category>
      <category>programming</category>
    </item>
    <item>
      <title>gopls MCP in vscode</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Mon, 08 Sep 2025 03:15:21 +0000</pubDate>
      <link>https://dev.to/pallat/gopls-mcp-in-vscode-1341</link>
      <guid>https://dev.to/pallat/gopls-mcp-in-vscode-1341</guid>
      <description>&lt;p&gt;พอดีไปเจอ blog นี้ &lt;a href="https://dev.to/calvinmclean/how-to-use-gopls-mcp-with-vs-code-11ha?utm_source=dormosheio&amp;amp;utm_campaign=dormosheio"&gt;How to use gopls MCP with VS Code&lt;/a&gt; เห็นว่าน่าสนใจเลยเอามาทดลองทำดู เลยอยากมาอธิบายซ้ำอีกรอบ&lt;/p&gt;

&lt;p&gt;ก่อนอื่นเลย gopls อ่านว่า "Go please" เป็น Language Server ที่พัฒนาโดย Go team มีหน้าที่เป็นตัวช่วย IDE ให้ช่วยตรวจสอบโค้ดที่เขียนด้วย Go ซึ่งถ้าเราใช้ vscode เวลาที่เราติดตั้ง Go extension มันก็จะขอให้เราติดตั้ง gopls ด้วย โดยในเวอร์ชั่นที่ v0.20.0 ก็ได้รวมเอา MCP server เข้ามา ซึ่งสามารถไปอ่าน doc ได้ที่ &lt;a href="https://tip.golang.org/gopls/features/mcp" rel="noopener noreferrer"&gt;Gopls: Model Context Protocol support&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ทีนี้เราก็จะมาทำให้ feature นี้สามารถทำงานบน vscode ได้ด้วย โดยขั้นตอนแรก จะต้องทำให้เครื่องเรามี gopls ตัวล่าสุดเสียก่อน โดยที่ถ้าเราจะติดตั้งเองก็สามารถทำได้ด้วยคำสั่ง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;golang.org/x/tools/gopls@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หรือไปสั่งใน vscode ก็ได้ ด้วยการเปิด command palette (command + shift + p) เลือก &lt;code&gt;Go: Install/Update Tools&lt;/code&gt; เลือก &lt;code&gt;gopls@latest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3a77afl1bj1vq3v43l26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3a77afl1bj1vq3v43l26.png" alt="Go: Install/Update Tools" width="794" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5y06a2som5dhi5vqb2gn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5y06a2som5dhi5vqb2gn.png" alt="gopls@latest" width="800" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;จากนั้นเราจะไปเพิ่ม flag ให้กับ gopls ใน vscode settings กัน โดยให้เราไปเปิด Settings แล้วเลือกเป็นแบบแก้ json file ตรงๆ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"go.useLanguageServer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"go.languageServerFlags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-mcp.listen=localhost:8092"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เราเพิ่ม flag นี้ &lt;code&gt;"-mcp.listen=localhost:8092"&lt;/code&gt; เข้าไป&lt;/p&gt;

&lt;p&gt;ขั้นตอนต่อมาเราก็ต้องไปเพิ่ม MCP Server ด้วยการไปที่ command palette (command + shift + p) อีกครั้ง แล้วเลือก &lt;code&gt;MCP: Add Server...&lt;/code&gt; เลือก &lt;code&gt;HTTP (HTTP or Server-Sent Events)&lt;/code&gt; แล้วใส่ URL ของ mcp เข้าไปแบบนี้ &lt;code&gt;http://localhost:8092&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;จากนั้นไปทดลองใช้งานกันได้เลย ด้วยการทดลองเขียนโค้ด&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แล้วไปเปิด Chat แล้วเราก็บอกให้มันวิเคราะห์ไฟล์นี้ให้หน่อย เช่น&lt;/p&gt;

&lt;p&gt;"Run diagnostics on this file"&lt;br&gt;
"diagnose this file"&lt;br&gt;
หรือ "ตรวจไฟล์นี้"&lt;/p&gt;

&lt;p&gt;โดยผมทดลองด้วย model หลายตัว ตัวที่แนะนำได้เหมือนตัวอย่างมากสุดผมใช้ &lt;code&gt;Gemini 2.5 Pro&lt;/code&gt; (ลองเมื่อวันที่ 8 Sep 2025 นะครับ)&lt;br&gt;
มันจะวิเคราะห์ให้และแนะนำให้แก้ไขตามนี้&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1h1fqup2yt2b80rur5ft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1h1fqup2yt2b80rur5ft.png" alt="result" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ที่ต้นทางของบทความนี้เขาทำ instruction ให้ github ไว้ด้วย ถ้าใครสนใจลองไปตามดูที่ต้นทางได้นะครับ หวังว่าจะเป็นประโยชน์&lt;/p&gt;

</description>
    </item>
    <item>
      <title>omitzero</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Tue, 11 Feb 2025 23:44:48 +0000</pubDate>
      <link>https://dev.to/pallat/omitzero-564a</link>
      <guid>https://dev.to/pallat/omitzero-564a</guid>
      <description>&lt;p&gt;จากที่เคยสัญญาไว้ว่าจะมาเขียนเรื่อง feature ใหม่ใน Go1.24.0 อันนึงที่ชื่อ omitzero ที่จะมาให้ใช้กับ package &lt;code&gt;encoding/json&lt;/code&gt; โดยถ้าใครเคยใช้ omitempty มาก่อน ก็จะมีวิธีใช้งานเหมือนกัน และเพื่อให้เข้าใจง่าย เรามาเขียนโค้ดทดสอบง่ายๆกันก่อน&lt;br&gt;
ตัวอย่างแรก จะเป็นการสร้าง struct ขึ้นมาตัวหนึ่งหน้าตาแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Title&lt;/span&gt;       &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DateOfBirth&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;
    &lt;span class="n"&gt;Children&lt;/span&gt;    &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แล้วก็มาเขียนโค้ดง่ายๆเพื่อสร้าง json message จาก struct นี้ โดยเราจะกำหนดค่าให้แค่ field เดียว&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Pallat"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarshalIndent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แล้วทดลองรันด้วยคำสั่ง &lt;code&gt;go run main.go&lt;/code&gt; จะเห็นผลลัพธ์แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pallat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"DateOfBirth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0001-01-01T00:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Children"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เราจะเห็นว่า บางค่าที่เราไม่ได้กำหนดค่าให้ แต่เมื่อเราสร้าง json message ออกมา เรากลับได้เห็น message ของ field นั้นพร้อมค่าบางอย่างเช่น  Title เป็นค่า null เนื่องจาก type ของมันเป็น *string ซึ่งพอเป็น pointer มันก็จะแสดงคำว่า &lt;code&gt;null&lt;/code&gt; ออกมา และพฤติกรรมนี้แหล่ะ ที่แต่เดิม ถ้าเราไม่ต้องการจะเห็นมัน เราก็จะติด tag คำว่า &lt;code&gt;omitempty&lt;/code&gt; เข้าไป โดยเราจะมาทดลองติด tag นี้ให้กับทุกๆ field ดูกัน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"name,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;Title&lt;/span&gt;       &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;   &lt;span class="s"&gt;`json:"title,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;DateOfBirth&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt; &lt;span class="s"&gt;`json:"dob,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;Children&lt;/span&gt;    &lt;span class="kt"&gt;int&lt;/span&gt;       &lt;span class="s"&gt;`json:"children,omitempty"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ส่วนโค้ดเราก็จะเปลี่ยนเอาค่า Name ออกไปด้วยเลย จะได้เห็นพฤติกรรมของ string และ *string ด้วย&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarshalIndent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ผลลัพธ์ที่ได้จะเป็นแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0001-01-01T00:00:00Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หมายความว่าโดยปกติ แม้แต่ basic type ถ้ามันมีค่าเป็น zero value เพียงแค่เราติด  tag omitempty เข้าไป เวลาที่ Marshal ออกมามันจะ omitted ค่าใน field นั้นให้เลย  ซึ่งเดิม เราก็จะมาติดปัญหาตรง type ที่มันมีโครงสร้างเช่น time.Time นี่แหล่ะที่ต่อให้เราติด &lt;code&gt;omitempty&lt;/code&gt; เข้าไปแล้ว เราก็จะยังเห็นค่าแบบนี้อยู่ดี ทีนี้เราจะลองมาติด tag &lt;code&gt;omitzero&lt;/code&gt; เข้าไปเพิ่มดูแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"name,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;Title&lt;/span&gt;       &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;   &lt;span class="s"&gt;`json:"title,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;DateOfBirth&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt; &lt;span class="s"&gt;`json:"dob,omitempty,omitzero"`&lt;/span&gt;
    &lt;span class="n"&gt;Children&lt;/span&gt;    &lt;span class="kt"&gt;int&lt;/span&gt;       &lt;span class="s"&gt;`json:"children,omitempty"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แล้วเรารันโค้ดชุดเดิม ผลลัพธ์จะกลายเป็น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ส่วนตัวผมคิดว่าบางอย่างอาจจะไม่ได้เป็นไปตาม document ยกตัวอย่างเช่นค่า int ที่ถ้าเราไม่กำหนดค่าให้ แล้วโดยปกติมันจะมี zero value เป็น &lt;code&gt;0&lt;/code&gt; การติด &lt;code&gt;omitempty&lt;/code&gt; มันไม่ควรทำให้ค่านี้หายไป แต่ตอนนี้ถ้าเราทดลองดูก็จะเห็นว่ามันหายไปด้วยแล้ว&lt;br&gt;
แต่ก็ไม่เป็นปัญหา ถ้าเราอยากเห็นเลย &lt;code&gt;0&lt;/code&gt; เราก็เอา tag ออกก็ใช้ได้&lt;/p&gt;

&lt;p&gt;ส่วนที่ doc พยายามอธิบายคือ ถ้าเราติด &lt;code&gt;omitempty&lt;/code&gt; มันจะดูที่ตัว message ของ json ว่าถ้าค่าที่ได้มาได้ค่่าเช่น null หรือ string, object หรือ array ที่ว่างเปล่า มันจะ omitted ให้&lt;/p&gt;

&lt;p&gt;ส่วน &lt;code&gt;omitzero&lt;/code&gt; จะมีผลกับค่า zero value ของ Go เอง เช่น time.Time ที่เราไม่ได้กำหนดค่าให้มัน มันจะ omitted ให้ และจะมีผลกับค่าที่มเมธอด &lt;code&gt;IsZero() bool&lt;/code&gt; ด้วยเช่นกัน&lt;/p&gt;

&lt;p&gt;ทีนี้เราลองทดลองค่าที่เป็น int กันดูว่า ถ้าเรามีเงื่อนไขให้มันเช่น ถ้าค่าที่ได้มีค่าตั้งแต่ &lt;code&gt;0&lt;/code&gt; ขึ้นไป เราจะแสดงค่าเหล่านั้นออกมาใน json message และในทางกลับกันถ้าได้ค่าติดลบใดใดเราจะ omitted มัน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"name,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;Title&lt;/span&gt;       &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;   &lt;span class="s"&gt;`json:"title,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;DateOfBirth&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt; &lt;span class="s"&gt;`json:"dob,omitempty,omitzero"`&lt;/span&gt;
    &lt;span class="n"&gt;Children&lt;/span&gt;    &lt;span class="n"&gt;Int&lt;/span&gt;       &lt;span class="s"&gt;`json:"children,omitzero"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Int&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;IsZero&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;โดยเราสร้าง type ใหม่ที่ชื่อ Int และเอาไปใช้กับ field ชื่อ Children โดยเราใส่เงื่อนไขใน &lt;code&gt;IsZero&lt;/code&gt; ว่าถ้าค่าน้อยกว่า 0 จะคืนค่า &lt;code&gt;false&lt;/code&gt; ออกมา&lt;br&gt;
แล้วเปลี่ยน tag เป็น &lt;code&gt;omitzero&lt;/code&gt; ดู จากนั้นเราก็รันโค้ดชุดเดิม ก็จะได้ผลลัพธ์แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เอาละครับ หลักๆแล้ว เราก็ได้ของที่อำนวยความสะดวกมาให้เราเพิ่มอย่างหนึ่ง อย่างน้อยเวลาเราจะต้องสร้าง json message ที่มี type ซับซ้อน เราก็ยังมีตัวช่วยให้ชีวิตง่ายขึ้นมาอีกหน่อย แต่เพื่อความชัวร์ เวลาเขียนก็ลองทดสอบพฤติกรรมมันให้มั่นใจดูก่อนนะครับ หวังว่าจะเป็นประโยชน์&lt;/p&gt;

</description>
    </item>
    <item>
      <title>&lt;/&gt; htmx handle array response</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Tue, 15 Oct 2024 08:21:19 +0000</pubDate>
      <link>https://dev.to/pallat/handle-array-response-2147</link>
      <guid>https://dev.to/pallat/handle-array-response-2147</guid>
      <description>&lt;p&gt;จากคราวก่อนที่เราสามารถรับ json response มาแสดงผลใน html ได้แล้ว แต่ถ้าเกิดว่า response นั้นส่งกลับมาเป็น array ล่ะ เราจะจัดการมันแบบไหนดี เรามาดูตัวอย่างกัน&lt;/p&gt;

&lt;p&gt;index.html&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx.org@2.0.3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx.org@1.9.12/dist/ext/json-enc.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx-ext-client-side-templates@2.0.0/client-side-templates.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mustache@latest"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;hx-ext=&lt;/span&gt;&lt;span class="s"&gt;"client-side-templates"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;hx-post=&lt;/span&gt;&lt;span class="s"&gt;"/api"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"innerHTML"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#content"&lt;/span&gt; &lt;span class="na"&gt;hx-ext=&lt;/span&gt;&lt;span class="s"&gt;"json-enc"&lt;/span&gt; &lt;span class="na"&gt;mustache-array-template=&lt;/span&gt;&lt;span class="s"&gt;"mytemplate"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Leave a comment here"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;replace here&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"mytemplate"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        {{#data}}
        &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt; {{message}} {{name}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        {{/data}}
    &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;main.go&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"test message #1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;"test name #1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"test message #2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;"test name #2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8910"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากตัวอย่างนี้ เราแก้ให้ API คืน response ออกมาเป็น array 2 records&lt;br&gt;
ส่วนที่ html เราใช้ htmx เหมือนตอนที่เรารับ json object ปกติเลย&lt;br&gt;
สิ่งที่ต่างไปจากเดิมก็คือ &lt;code&gt;mustache-template="mytemplate"&lt;/code&gt; เป็น &lt;code&gt;mustache-array-template="mytemplate"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;แล้วที่ template ให้ใส่ &lt;code&gt;{{#data}}&lt;/code&gt; ครอบแล้วปิดด้วย &lt;code&gt;{{/data}}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{#data}}
  &lt;span class="c"&gt;&amp;lt;!-- fields --&amp;gt;&lt;/span&gt;
{{/data}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;นอกนั้นก็จัดรูปแบบไว้ มันจะ repeat ของใน array ไปจนกว่าจะหมด&lt;/p&gt;

&lt;p&gt;ถึงตอนนี้ เราก็น่าจะใช้ htmx จัดการ request/response ในรูปแบบ json เบื้องต้นได้ค่อนข้างครอบคลุมแล้วนะครับ หวังว่าจะเป็นประโยชน์&lt;/p&gt;

</description>
      <category>htmx</category>
    </item>
    <item>
      <title>&lt;/&gt; htmx handle json response</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Tue, 15 Oct 2024 08:09:27 +0000</pubDate>
      <link>https://dev.to/pallat/handle-json-response-51op</link>
      <guid>https://dev.to/pallat/handle-json-response-51op</guid>
      <description>&lt;p&gt;คราวนี้เราจะลองมาดูวิธีการรับ json response ที่เราได้รับมาจาก API เพื่อมาแสดงผลที่หน้าจอเราแบบง่ายๆกันดู โดยเราจะนำโค้ดจากครั้งที่แล้วมาเติมของให้ดูแบบนี้&lt;/p&gt;

&lt;p&gt;index.html&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx.org@2.0.3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx.org@1.9.12/dist/ext/json-enc.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx-ext-client-side-templates@2.0.0/client-side-templates.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mustache@latest"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;hx-ext=&lt;/span&gt;&lt;span class="s"&gt;"client-side-templates"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;hx-post=&lt;/span&gt;&lt;span class="s"&gt;"/api"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"innerHTML"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#content"&lt;/span&gt; &lt;span class="na"&gt;hx-ext=&lt;/span&gt;&lt;span class="s"&gt;"json-enc"&lt;/span&gt; &lt;span class="na"&gt;mustache-template=&lt;/span&gt;&lt;span class="s"&gt;"mytemplate"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Leave a comment here"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;replace here&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"mytemplate"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt; {{message}} {{name}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นไปดู API แบบง่ายๆเพื่อทำการทดสอบกัน&lt;/p&gt;

&lt;p&gt;main.go&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"test message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;"test name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8910"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หน้าที่ของ API มีเพียงการรับ request เข้ามาแล้วตอบ json message ออกไปง่ายๆ โดยหน้าตาของ response จะเป็นแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test name"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ทีนี้เรามาดูตอนรับไปแสดงผล ก่อนอื่นเราต้อง include ตัว extension เข้ามาก่อน 2 ตัวนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx-ext-client-side-templates@2.0.0/client-side-templates.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mustache@latest"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นให้ครอบตั้งแต่ form ไปจนถึง target id และ template ด้วย&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;hx-ext=&lt;/span&gt;&lt;span class="s"&gt;"client-side-templates"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพื่อเป็นการบอกว่าเราต้องการจะ render ด้วย client-side-templates&lt;/p&gt;

&lt;p&gt;ที่ form เราระบุ &lt;code&gt;mustache-template="mytemplate"&lt;/code&gt; เพื่อบอกว่า response ที่ได้ เราจะใช้ mustache-template เป็น template ในการแสดงผล&lt;/p&gt;

&lt;p&gt;จากนั้นใน template เราสามารถระบุชื่อ field ที่ได้จาก response แบบนี้&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{{message}}&lt;/code&gt; หมายถึง field ที่ชื่อ message จาก response เลยเป็นต้น&lt;/p&gt;

&lt;p&gt;เพียงเท่านี้เราก็สามารถนำ response date มาแสดงผลตามที่เราต้องการได้แล้วครับ&lt;/p&gt;

</description>
    </item>
    <item>
      <title>&lt;/&gt; htmx post json</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Tue, 15 Oct 2024 07:43:09 +0000</pubDate>
      <link>https://dev.to/pallat/-htmx-post-json-2kj</link>
      <guid>https://dev.to/pallat/-htmx-post-json-2kj</guid>
      <description>&lt;p&gt;ต่อจากคราวที่แล้วที่เราพาไปทำความรู้จัก htmx แบบเร็วๆ มาคราวนี้จะพามาดูวิธีส่ง json request ไปให้ API ซึ่ง htmx อย่างเดียวจะไม่เพียงพอต่อการทำงานนี้ละ เราเลยจะต้องใช้ตัวช่วย โดย htmx จะเตรียมบรรดาเหล่า extensions ไว้ให้เราใช้อยู่ด้วย ไปดูได้จาก &lt;a href="https://v1.htmx.org/docs/#extensions" rel="noopener noreferrer"&gt;link&lt;/a&gt; นี้&lt;/p&gt;

&lt;p&gt;โดยตัวที่เราจะหยิบมาใช้ตอนนี้ก็คือ &lt;a href="https://v1.htmx.org/extensions/json-enc/" rel="noopener noreferrer"&gt;json-enc&lt;/a&gt; โดยหน้าที่ของมันก็คือ เวลาเราต้องการจะยิง request ไปหา API สักตัว โดยจะส่งข้อมูลไปให้อยู่ในรูปแบบของ json เราก็จะใช้วิธีสร้าง form ขึ้นมาชุดหนึ่ง เวลาที่เราใช้ json-enc มันจะทำการ serialize ของใน form ไปอยู่ในรูปแบบของ json ให้เอง เรามาดูวิธีทำกันเลย&lt;/p&gt;

&lt;p&gt;index.html&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx.org@2.0.3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx.org@1.9.12/dist/ext/json-enc.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;hx-post=&lt;/span&gt;&lt;span class="s"&gt;"/api"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"innerHTML"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#content"&lt;/span&gt; &lt;span class="na"&gt;hx-ext=&lt;/span&gt;&lt;span class="s"&gt;"json-enc"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Leave a comment here"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;replace here&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;นี่คือในส่วนของ html ซึ่งจะสามารถส่ง request ไปให้ api ได้แล้ว ต่อมาเราจะมาเขียน API แบบง่ายสุดๆด้วย Go ตามนี่ครับ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8910"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อเขียนเสร็จ เราจะรันมันด้วยกันผ่าน go ด้วยคำสั่งนี้ครับ&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;go run main.go&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ทีนี้เราจะไปเปิดหน้า web ผ่าน url ใหม่ &lt;a href="http://localhost:8910/" rel="noopener noreferrer"&gt;http://localhost:8910/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;พอเราทดลองกด submit แล้วไปดูที่ console ที่เรารัน go run main.go เอาไว้ เราก็จะเห็น log ที่มีหน้าตาแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"sss"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"ddd"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สิ่งที่ต้องไม่ลืมคือการนำ extension เข้ามาใช้ ตามตัวอย่างเราใช้ CDN ใน script&lt;br&gt;
ถ้าเราลืม extension สิ่งที่เราจะได้ก็จะกลายเป็น request ลักษณะแบบ form แทนแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;message=sss&amp;amp;name=ddd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากตัวอย่างข้างต้นนี้ เราก็จะสามารถใช้ htmx ทำการส่ง request ในรูปแบบ json ได้แล้ว&lt;/p&gt;

</description>
      <category>htmx</category>
    </item>
    <item>
      <title>&lt;/&gt; htmx in 5 minutes</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Tue, 15 Oct 2024 03:42:00 +0000</pubDate>
      <link>https://dev.to/pallat/-htmx-in-5-minutes-2l57</link>
      <guid>https://dev.to/pallat/-htmx-in-5-minutes-2l57</guid>
      <description>&lt;p&gt;&amp;lt;/&amp;gt; htmx เป็น library ที่ช่วยให้เราสามารถใช้ AJAX, CSS Transitions, WebSockets และ SSE ได้โดยตรงผ่าน HTML&lt;/p&gt;

&lt;p&gt;ถ้าให้เล่าแบบง่ายๆก็คือ แทนที่เราจะไปเขียน Framework อย่าง ReactJS, Vue หรือ Angular เราสามารถทำงานง่ายๆผ่านการใช้ htmx ซึ่งส่วนใหญ่จะเขียนในรูป html, js และ css อย่างละนิดอย่างละหน่อย ยกตัวอย่างเช่น ถ้าเราต้องการจะให้หน้า web ไปยิง API สักเส้น แล้วรับค่า json กลับมาแสดง ก็สามารถทำได้&lt;/p&gt;

&lt;p&gt;ผมจะลองยกตัวอย่างการใช้งานง่ายๆที่ทุกคนน่าจะทำตามได้&lt;br&gt;
เริ่มจากการสร้างไฟล์มา 2 files&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;index.html&lt;/li&gt;
&lt;li&gt;hello.html&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;index.html&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx.org@2.0.3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/hello.html"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"outerHTML"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Click Me
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;replace here&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;hello.html&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
Hello
&lt;span class="nt"&gt;&amp;lt;/div&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ที่เหลือก็ลองทดสอบ โดยผมจะใช้ &lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer" rel="noopener noreferrer"&gt;Live Server&lt;/a&gt; นะครับ ใครติดตั้งแล้วก็เปิด Command Palette  แล้วเลือก &lt;code&gt;Live Server: Open with Live Server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdbbhgzgb67syd5osx6v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdbbhgzgb67syd5osx6v.png" alt="Image description" width="304" height="62"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;โดยปกติมันก็จะเปิด browser ขึ้นมาให้เราเลยที่ &lt;code&gt;127.0.0.1:5500/index.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;เราก็จะเห็นปุ่มแบบนี้&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhdcxkyol384ienqhm15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhdcxkyol384ienqhm15.png" alt="Image description" width="214" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ทดลองกดปุ่ม &lt;code&gt;Click Me&lt;/code&gt; ก็จะเห็นข้อความ Hello มาแทน replace here&lt;/p&gt;

&lt;p&gt;โดยเมื่อดูจากโค้ดที่เราเขียนมันเริ่มจากการ include ตัว htmx script เข้ามาก่อน ทีนี้ใน tag button เราเพิ่ม &lt;code&gt;hx-get&lt;/code&gt; เข้าไปเพื่อบอกมันว่า เมื่อกดปุ่มให้ไปเรียก http request หาอะไร โดยในที่นี้เราเอาง่ายสุด แทนที่จะไปยิง API เราก็แค่เรียกไปที่ html ตัวหนึ่ง&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hx-swap&lt;/code&gt; ตัวนี้เราบอกมันว่า เมื่อได้ผลลัพธ์มาแล้ว จะให้ไปสลับตำแหน่งกับจุดหมายปลายทางแบบไหน โดยเราใส่ไปว่า &lt;code&gt;outerHTML&lt;/code&gt; หมายความว่า id ปลายทางทั้งก้อนจะถูกแทนที่ด้วย response เลย และสุดท้าย&lt;br&gt;
&lt;code&gt;hx-target&lt;/code&gt; ก็คือ id ปลายทางที่่เราจะเอา response ไปแสดงนั่นเอง&lt;/p&gt;

&lt;p&gt;ทีนี้ ถ้าเรามาลองแก้ &lt;code&gt;hx-swap&lt;/code&gt; เป็น &lt;code&gt;innerHTML&lt;/code&gt; ดู มันจะเปลี่ยนเป็นการนำเอา response มาแทนที่ของที่อยู่ใน id ปลายทาง โดยที่ tag ของ id ปลายทางจะยังคงอยู่&lt;br&gt;
เราก็ลองไปเปลี่ยนไฟล์ &lt;code&gt;hello.html&lt;/code&gt; อีกนิด โดยไปลบ html tag ออก ให้เหลือแค่ข้อความอย่างเดียว แล้วทดลองใหม่ ก็จะเห็นว่ามันก็แสดงผลเหมือนเดิม&lt;/p&gt;

&lt;p&gt;การใช้งานนี้เป็นแบบเริ่มต้น เดี๋ยวคราวหน้าเราจะมาลองยิง API แล้วรับส่งข้อมูลแบบ json กันดูครับ&lt;/p&gt;

</description>
      <category>htmx</category>
    </item>
    <item>
      <title>Makefile ep.1</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Sun, 08 Sep 2024 03:54:21 +0000</pubDate>
      <link>https://dev.to/pallat/makefile-ep1-3ic4</link>
      <guid>https://dev.to/pallat/makefile-ep1-3ic4</guid>
      <description>&lt;p&gt;เนื่องจากที่ผ่านมาเวลาทำ code repo ส่วนใหญ่ก็มักจะเขียน Makefile ใส่เข้าไปด้วย เพื่ออำนวยความสะดวก และอีกเหตุผลหนึ่งคือ คำสั่งบางอย่างมันยาว ก็เลยเขียนใส่ Makefile เอาไว้ เพราะขี้เกียจไปตาม googling มาใหม่นั่นเองครับ ที่มาที่ไปของการใช้ Makefile ของผมก็เป็นเช่นนี้ และไหนๆก็ใช้บ่อยแล้ว น้องๆหลายคนอาจจะเคยเข้ามาเห็นอยู่บ้าง ใช้เป็นบ้างก็ตามๆพี่ๆไป ก็เลยคิดว่า เอามาอธิบายจริงจังให้เข้าใจกันสักยกก็น่าจะดี&lt;/p&gt;

&lt;p&gt;โดยเนื้อหาหลักตอนนี้จะเริ่มด้วยการพาไปรู้จักวิธีใช้ตามคู่มือของ &lt;a href="https://www.gnu.org/software/make/manual/make.html" rel="noopener noreferrer"&gt;GNU make manual&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  รูปแบบการเขียน Makefile
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;target … &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;prerequisites …&lt;/span&gt;
        recipe
        …
        …
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากที่เห็นนี้อธิบายว่า &lt;code&gt;target&lt;/code&gt; คือชื่อของคำสั่ง เวลาที่เราใช้คำสั่ง make ผมจะยกตัวอย่างจริงให้ดูเพื่อเทียบกันตามนี้นะ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;start&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hello"&lt;/span&gt;
&lt;span class="nl"&gt;show&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Welcome to the Makefile tutorial"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ในที่นี้ &lt;code&gt;target&lt;/code&gt; ของเราคือคำว่า &lt;code&gt;start&lt;/code&gt; และ &lt;code&gt;show&lt;/code&gt; ซึ่งเวลาที่เราอยากจะสั่งให้มันไปทำงานที่ target ชื่อ start เราก็จะสั่งว่า &lt;code&gt;make start&lt;/code&gt; แบบนี้นะครับ&lt;/p&gt;

&lt;p&gt;&lt;code&gt;prerequisites&lt;/code&gt; จากตัวอย่าง target &lt;code&gt;show&lt;/code&gt; ผมเขียนให้มันมี prerequisites เป็น &lt;code&gt;start&lt;/code&gt; หมายความว่า ถ้าเราสั่งคำสั่ง &lt;code&gt;make show&lt;/code&gt; สิ่งที่เกิดขึ้นคือ มันจะไปทำคำสั่ง &lt;code&gt;make start&lt;/code&gt; ให้เราก่อน เสร็จแล้วมันถึงจะมาทำตาม &lt;code&gt;recipe&lt;/code&gt; ที่อยู่ใน &lt;code&gt;show&lt;/code&gt; ต่อ&lt;br&gt;
ซึ่งในที่นี้ &lt;code&gt;recipe&lt;/code&gt; ของทั้ง 2 target เราทำเพียงแค่สั่ง &lt;em&gt;echo&lt;/em&gt; ให้มันแสดงข้อความออกมาง่ายๆเท่านั้น&lt;/p&gt;

&lt;p&gt;การตั้งชื่อไฟล์ของ &lt;strong&gt;Makefile&lt;/strong&gt; เราสามารถตั้งว่า &lt;code&gt;Makefile&lt;/code&gt; ก็ได้หรือ &lt;code&gt;makefile&lt;/code&gt; ก็ได้เช่นกัน แต่ส่วนตัวผมชอบตั้งว่า &lt;code&gt;Makefile&lt;/code&gt; มากกว่า ซึ่งถ้าอ่าน doc ก็จะแนะนำแบบเดียวกันครับ&lt;/p&gt;

&lt;p&gt;&lt;code&gt;recipe&lt;/code&gt; เราได้เห็นจากตัวอย่างนะครับว่า recipe ในตัวอย่างจะเป็นแบบโคตรง่ายเลย ก็คือสั่ง &lt;em&gt;echo&lt;/em&gt; หรือก็คือสั่งพิมพ์ข้อความออกมาให้เราเห็นง่ายๆ สิ่งสำคัญของการวาง recipe ก็มีเพียง เราจะต้องมี indent และต้องเป็น tab เท่านั้น จะมา space ไม่ได้นะ&lt;/p&gt;

&lt;p&gt;ทีนี้เราก็จะสามารถเริ่มต้นเขียน Makefile เบื้องต้นง่ายๆเราได้แล้ว โดยเราจะเอาไปสั่งทำอะไรก็ได้ยกตัวอย่างเช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;go&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"run Go program"&lt;/span&gt;
    go run main.go
&lt;span class="nl"&gt;install&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"install nodejs dependencies"&lt;/span&gt;
    npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หวังว่าจะเป็นประโยชน์นะครับ&lt;/p&gt;

</description>
      <category>makefile</category>
    </item>
    <item>
      <title>จัดการ Go dependencies tools ด้วย Go mod</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Sat, 07 Sep 2024 02:33:59 +0000</pubDate>
      <link>https://dev.to/pallat/cchadkaar-go-dependencies-tools-dwy-go-mod-g91</link>
      <guid>https://dev.to/pallat/cchadkaar-go-dependencies-tools-dwy-go-mod-g91</guid>
      <description>&lt;p&gt;พอดีว่าไปเจอ repo หนึ่ง &lt;a href="https://github.com/golang-templates/seed" rel="noopener noreferrer"&gt;https://github.com/golang-templates/seed&lt;/a&gt; เขามีวิธีจัดการ tools ที่เขาใช้ในการ dev Go ผ่าน Go Module ซึ่งดูแล้วน่าสนใจเลยเอามาเล่าให้ฟัง&lt;/p&gt;

&lt;p&gt;จาก repo นี้เขาใช้วิธีสร้าง go module ซ้อนไว้ใน project อีกชั้นหนึ่งแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./
├── go.mod
├── go.sum
├── main.go
├── tools
│   ├── go.mod
│   ├── go.sum
│   └── tools.go

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แล้วเขียน Makefile กำกับไว้แบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;inst&lt;/span&gt;
&lt;span class="nl"&gt;inst&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; go install tools&lt;/span&gt;
    &lt;span class="nb"&gt;cd &lt;/span&gt;tools &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;shell &lt;span class="nb"&gt;cd &lt;/span&gt;tools &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go list &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s1"&gt;'{{ join .Imports " " &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;}'&lt;/span&gt; &lt;span class="nt"&gt;-tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tools&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เขาเขียนไว้ว่า ถ้ารันคำสั่ง &lt;code&gt;make inst&lt;/code&gt; มันจะ cd เข้าไปใน tools แล้วสั่ง go install ของที่อยู่ใน import ลงมา&lt;br&gt;
ซึ่งมันเวิร์คโดยเฉพาะกับ tools ต่างๆที่เขียนด้วย Go เหมือนกัน เช่น govulncheck หรือ golangci-lint เป็นต้น แต่ถ้าเป็นพวก tools ที่เขียนด้วยภาษาอื่น อันนี้ทำไม่ได้แน่นอน&lt;/p&gt;

&lt;p&gt;จากที่ทดลอง มันติดอยู่อย่างหนึ่ง ถ้าเราเขียน repo แบบนี้ แล้วตั้งใจอยากจะทำเป็น template ให้คนอื่นมาสั่ง &lt;a href="https://go.dev/blog/gonew" rel="noopener noreferrer"&gt;gonew&lt;/a&gt; ไปใช้ต่อ มันจะไม่สามารถเอา /tools ติดไปด้วยได้ แต่ก็เป็นแนวทางที่น่าสนใจดี สำหรับการนำไปใช้กับโปรเจคทั่วไปครับ&lt;/p&gt;

</description>
    </item>
    <item>
      <title>เขียน Go ให้เรียบง่าย บางทีก็ยาก</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Tue, 03 Sep 2024 09:58:07 +0000</pubDate>
      <link>https://dev.to/pallat/ekhiiyn-go-aiheriiybngaay-baangthiikyaak-2gh5</link>
      <guid>https://dev.to/pallat/ekhiiyn-go-aiheriiybngaay-baangthiikyaak-2gh5</guid>
      <description>&lt;p&gt;ช่วงนี้ผมกำลังพยายามทำ example repo ให้น้องๆในที่ทำงานดูเป็นตัวอย่าง โดยแนวคิดแรกเลยก็คือ simplify&lt;/p&gt;

&lt;p&gt;แต่การจะ simplify สำหรับคนบางกลุ่ม มันจะยากมาก ก.ไก่หลายตัว เพราะมันจะขัดความรู้สึกเขา และเขารู้สึกว่า การทำแบบนั้นมันบาป ผิดศีลทุกข้อที่เคยปฏิบัติมาอย่างเคร่งครัด&lt;br&gt;
ผมรู้ได้ไง ก็เพราะคำถามที่เขาตั้ง หลายๆคน หลายๆครั้ง จะตั้งคำถามคล้ายๆกันเช่น&lt;/p&gt;

&lt;p&gt;พี่ครับ แล้ว repository ผมจะเขียนยังไง&lt;br&gt;
พี่ครับ repository ผมจะวางไว้ตรงไหน&lt;br&gt;
พี่ครับ ถ้ามี service 2 ตัวผมจะสร้าง interface ยังไง&lt;br&gt;
พี่ครับ ถ้าผมเขียนแบบนี้แล้ว ชั้นของ adapter ผมจะเอาไปวางไว้ที่ไหน&lt;/p&gt;

&lt;p&gt;คำถามพวกนี้มันทำให้ผมรู้สึกถึงความเจ็บปวดของเขาได้จริงๆ ผมไม่รู้จะตอบเขายังไงดีว่า ลูกเอ้ย เราไม่ได้อยู่กับพระเจ้าแล้วนะลูก ตอนนี้เราขายวิญญาณให้ซาตานเป็นที่เรียบร้อยแล้ว และตอนนี้เจ้ากำลังอยู่ในนรกนะงี้&lt;/p&gt;

&lt;p&gt;ผมยกตัวอย่าง handler มาให้ดูสักตัวหนึ่ง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;B2CHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="n"&gt;B2C&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ShouldBindJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MakeOrder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="m"&gt;5001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่างนี้เป็นตัวอย่างสมมุตินะครับ มันไม่สมบูรณ์ โดยในนี้มีเรียก payment interface อยู่ตัวหนึ่ง ซึ่งผมเขียนทุกอย่างอยู่ใน pacakge เดียวกัน&lt;/p&gt;

&lt;p&gt;ครับ มาถึงตรงนี้ คนที่รู้สึกว่าบาป ก็จะเห็นแล้ว ส่วนคนที่ไม่รู้สึกอะไร เรามากอดคอกัน 555&lt;/p&gt;

&lt;p&gt;ความรู้สึกบาปนี้ ผมบอกได้แค่ว่า เราจะต้องวางสิ่งที่ทำให้เรารู้สึกบาปไว้ข้างๆตัวก่อน ไว้เขียน Go จบแล้ว เวลาจะไปเขียนภาษาอื่นค่อยเอามาสวมไว้เหมือนเดิม มันจะพอช่วยเราได้บ้าง อย่าไปเครียด เดี๋ยวมันจะดีเอง&lt;/p&gt;

&lt;p&gt;มันจะไม่มีคำที่เราคุ้นๆเช่น service, repository, model และผองเพื่อนอยู่ในนี้เลย ซึ่งผมจะบอกให้ว่า มันทำงานได้นะ ไม่ต้องมีคำพวกนั้นมันก็ทำงานได้ ขอให้มั่นใจในสิ่งที่เขียน ไม่ต้องมีสิ่งศักสิทธิ์เหล่านั้นมันก็อยู่ได้ครับจริงๆ&lt;/p&gt;

</description>
    </item>
    <item>
      <title>range-over-func in Go</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Sun, 18 Aug 2024 11:07:09 +0000</pubDate>
      <link>https://dev.to/pallat/range-over-func-in-go-oof</link>
      <guid>https://dev.to/pallat/range-over-func-in-go-oof</guid>
      <description>&lt;p&gt;Go1.23 ได้นำฟีเจอร์ range-over-func ที่เป็น experiment ใน go1.22 มาให้ใช้จริง ซึ่งถ้าใครได้อ่านโค้ดตัวอย่างเข้าไปแล้วอาจจะต้องนั่งสมาธิกันนานหน่อย อย่ากระนั้นเลย พี่ยอดจะมาอธิบายแบบง่ายสุดๆให้อ่านกัน&lt;/p&gt;

&lt;p&gt;เริ่มจาก spec ของ &lt;a href="https://go.dev/ref/spec#For_range" rel="noopener noreferrer"&gt;For statements with range clause&lt;/a&gt; ได้เพิ่มเติม Expression เข้ามา 3 แบบคือ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;โดยพี่จะขอเพิ่มตัวแปรให้ตัวนึงเพิ่อจะได้อธิบายดังนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใน spec บอกว่า เมื่อเราใช้ฟังก์ชั่น f ไปเป็น expression ใน range ทุกครั้งที่เราเรียกฟังก์ชั่น yield ในนั้นก่อนจะจบฟังก์ชั่น f เราจะได้ผลลัพธ์ในแต่ละลูป เท่ากับค่าที่เราใส่เข้าไปใน yield อธิบายแล้วก็ยังงง เขียนโค้ดเลยดีกว่า&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;-
-
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้าเราเขียนโค้ดแบบนี้ เราจะได้ loop 2 รอบถ้วน เพราะเราเรียก yield 2 ครั้งใน f ตาม spec ซึ่งในที่นี่เราตั้งชื่อว่า &lt;code&gt;loop&lt;/code&gt; และมันจะไม่คืนค่าอะไรออกมาให้เรา เพราะเราเลือกใช้ pattern ที่ yield ไม่รับ arguments ใดๆเลย&lt;/p&gt;

&lt;p&gt;อีกตัวอย่าง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;3
7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แบบนี้เราจะได้ 2 รอบเหมือนกัน เพราะเราเรียก yield ครั้ง และทีนี้ range จะคืนค่ามาให้ 2 ค่า ซึ่งก็คือ 3 และ 7 ที่เราใช้เรียก yield ในแต่ละครั้ง&lt;/p&gt;

&lt;p&gt;อีกตัวอย่าง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"three"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"five"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"seven"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;3 three
5 five
7 seven
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เราก็จะได้ loop 3 รอบ และได้ค่าออกมารอบละ 2 ค่าตามที่เราใส่ให้ yield ในแต่ละครั้ง&lt;br&gt;
และเรายังสามารถเรียก yield ด้วยการใส่ arguments แบบไหนก็ได้เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"three"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"five"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"seven"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ทีนี้พอเราเข้าใจกลไกลของมันแล้ว เวลาเราไปอ่านตัวอย่างยากๆเราจะเข้าใจมากขึ้นเช่นตัวอย่างใน &lt;a href="https://go.dev/wiki/RangefuncExperiment#what-is-a-simple-example-of-how-range-over-function-runs" rel="noopener noreferrer"&gt;Go Wiki: Rangefunc Experiment&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;slices&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Backward&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;main&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"world"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;slices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Backward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;อ่านง่ายขึ้นเลยใช่ไหม สุดท้ายจะเอาไปประยุกต์ยังไงก็แล้วแต่ เราดูแค่ตอนที่เรียก yield ว่าเรียกกี่รอบ ก็จะได้เท่านั้นรอบตอนเอาไปใส่ใน range&lt;br&gt;
ส่วนค่าที่จะได้ออกมาก็คือค่าที่หย่อนลงไปใน yield นั่นแหล่ะ จบ&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>time format ใน Go</title>
      <dc:creator>Pallat Anchaleechamaikorn</dc:creator>
      <pubDate>Mon, 29 Jul 2024 04:38:49 +0000</pubDate>
      <link>https://dev.to/pallat/time-format-ain-go-4g23</link>
      <guid>https://dev.to/pallat/time-format-ain-go-4g23</guid>
      <description>&lt;p&gt;บังเอิญผมได้ไปเห็นการใช้ date time format ใน Go แบบผิดๆอยู่บ่อยๆ ก็เลยอยากมาอธิบายเรื่องนี้สักเล็กน้อย&lt;/p&gt;

&lt;p&gt;หลายคนอาจจะรู้อยู่แล้วว่าวิธีการจัดการ date time format ใน Go มันจะไม่เหมือนภาษาอื่นที่เขามักจะใช้อักษรแทนเช่น dd คือวันที่ MM คือเลขเดือน yyyy คือปี คศ 4 หลัก และในส่วนของเวลาก็ใช้ hh:mm อะไรแบบนี้ ใน Go จะใช้เลขเรียง 1 2 3 4 5 6 7 มาแทนเพื่อให้จำง่าย(ง่ายตรงไหน)&lt;br&gt;
ซึ่งก็มีหลายคนชื่นชมวิธีคิดแบบนี้ และในขณะเดียวกัน ก็มีคนสรรเสริญไปในทางลบค่อนข้างมากเช่นกัน ซึ่งเหตุผลในส่วนคนที่ชื่นชมก็มองว่า ถ้าคุณจำ magic order ได้ คุณก็ไม่ต้องจำมันอีกต่อไป ซึ่ง Rob Pike เคยมาเฉลยว่า เขาคิดเรื่องนี้ได้ตอนกลับบ้าน แล้วนึกถึงวิธีที่ภาษาโคบอลใช้ ซึ่งเรียกว่า Cobol picture clauses ทั้งๆที่เขาเองก็ไม่เคยเขียน Cobol นะ ส่วนคนที่ไม่ชอบก็ติว่า ทีใน fmt ใช้ %s %d กันสนุกเลย แต่พอมา time format กลับเลี่ยงที่จะทำเหมือนชาวบ้านเขาที่ใช้ %d %Y หรือ ddyy ทำไม มันทำให้ต้องมาจำอะไรแปลกๆเพิ่มขึ้นอีก ก็นะ ส่วนตัวผม ก็ดันชอบการคิดอะไรใหม่ๆอยู่แล้ว แต่ก็ไม่เถียงว่ามันก็ต้องมานั่งจำกันใหม่จริงๆนั่นแหล่ะ เอาล่ะมาเล่าเรื่อง time format กันต่อ โดยตัวแทนแต่ละเลขเป็นดังนี้&lt;/p&gt;

&lt;p&gt;1 = เดือน&lt;br&gt;
2 = วัน&lt;br&gt;
3 = ชั่วโมง&lt;br&gt;
4 = นาที&lt;br&gt;
5 = วินาที&lt;br&gt;
6 = ปี&lt;br&gt;
7 = time zone&lt;/p&gt;

&lt;p&gt;เห็นไหมว่ามันจำง่่าย (ย้ำว่าง่ายตรงไหน) เช่น "01/02 03:04:05PM '06 -0700" นี่คือหน้าตาของ format นะครับ ไม่ใช่เวลาจริง ส่วนเวลาจริง ถ้าตัวเลขตามนี้เป๊ะมันหมายถึง&lt;/p&gt;

&lt;p&gt;วันที่ 2 เดือน มกราคม ปี 2006 เวลา 15 นาฬิกา 4 นาที 5 วินาที ณ time zone ที่ -7 ซึ่งคือเวลาแถวๆประเทศเม็กซิโก ซึ่งตรงกับเวลา 22 นาฬิกา หรือ 4 ทุ่ม 4 นาที 5 วินาที ที่ตำแหน่ง UTC ที่ลอนดอน&lt;/p&gt;

&lt;p&gt;ทีนี้ เนื่องจาก format ที่ใส่ -0700 เข้าไปนี่ อาจจะทำให้คนที่ไม่ได้อ่าน doc ตีความกันไปเองว่า ไอ้แถวๆนี้มันน่าจะสามารถใส่อย่างอื่นเข้าไปแทนได้เช่น +0700 หรือ +0000 แต่ความจริง นี่มันเป็น format ซึ่งท่าบังคับมันคือจะต้องเป็น -0700 ไปใส่เครื่องหมาย + ให้มันไม่ได้จ้า และเลขก็ต้องเป็นเลข 7 ซึ่งเป็นเลขเรียงอย่างที่กล่าวไปแล้วข้างต้น&lt;/p&gt;

&lt;h2&gt;
  
  
  Month = 1
&lt;/h2&gt;

&lt;p&gt;สามารถใช้ได้ 4 รูปแบบ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jan กรณีต้องการเป็นอักษรย่อ 3 ตัว เช่นถ้า data เป็น Mar เราอยากจะ parse เข้ามาใส่ time.Time เราก็ต้องใช้ Jan แทนค่านั้นใน format&lt;/li&gt;
&lt;li&gt;January กรณีต้องการคำเต็มของเดือนเช่น ถ้า data เป็น March เราก็ต้องใช้ January เป็น format สำหรับ parse&lt;/li&gt;
&lt;li&gt;01 กรณีที่ data เป็นเลข 2 หลักแทนเดือน&lt;/li&gt;
&lt;li&gt;1 กรณีที่ data เป็นเลขที่ไม่ต้องการให้มี 0 นำหน้าสำหรับเดือนที่มี 1 digit เช่น เดือน มีนา ก็จะเป็นเลข 3 เลย&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Day = 2
&lt;/h2&gt;

&lt;p&gt;day จะพิเศษหน่อย เนื่องจากวันมีหลายความหมาย&lt;/p&gt;

&lt;h3&gt;
  
  
  วันในสัปดาห์เช่น จันทร์ อังคาร พุธ
&lt;/h3&gt;

&lt;p&gt;วิธีใช้ สามารถใช้ได้ทั้ง&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Mon"&lt;/li&gt;
&lt;li&gt;"Monday"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;จะมาใช้ "mon" แบบนี้ไม่ได้นะ&lt;/p&gt;

&lt;h3&gt;
  
  
  วันในเดือนก็คือวันที่
&lt;/h3&gt;

&lt;p&gt;สามารถใช้ได้ 3 รูปแบบคือ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"2"&lt;/li&gt;
&lt;li&gt;"02"&lt;/li&gt;
&lt;li&gt;"_2" ตัวนี้ถ้าเราจัด format ออกมาจะได้รูปแบบ 2 digits แต่ถ้าเป็นเดือนหลักเดียว มันจะเว้นวรรคให้เช่นถ้าเดือน 3 จะได้ " 3" แต่ถ้าเดือน 10 จะได้ "10" แบบนี้&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  วันที่ของปี ซึ่งมีได้ 365 หรือ 366 วัน
&lt;/h3&gt;

&lt;p&gt;มี 2 รูปแบบคือ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"002"&lt;/li&gt;
&lt;li&gt;"__2" ก็เหมือนวันของเดือน โดยจะเว้นวรรคและแสดงให้ครบ 3 digits&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hour = 3
&lt;/h2&gt;

&lt;p&gt;15" "3" "03" (PM or AM)&lt;br&gt;
มี 3 รูปแบบคือ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"15"&lt;/li&gt;
&lt;li&gt;"3" หรือ "3 PM"&lt;/li&gt;
&lt;li&gt;"03" หรือ "03 PM"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;การใส่ &lt;strong&gt;PM&lt;/strong&gt; จะช่วยเพิ่มรายละเอียดให้การบอกเวลาแบบ 12 hour clock ให้รู้ว่าเป็นเวลาก่อนเที่ยง(ante merīdiem หรือ “before midday”) หรือหลังเที่ยง(post merīdiem หรือ "before midday") ซึ่งจะไม่สามารถใช้ AM แทนได้นะ อย่าสับสน นี่คือการจัด format เด้อ มันบังคับให้ใช้ได้แค่ "PM"&lt;/p&gt;

&lt;h2&gt;
  
  
  Minute = 4
&lt;/h2&gt;

&lt;p&gt;มี 2 รูปแบบ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"4"&lt;/li&gt;
&lt;li&gt;"04"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Second = 5
&lt;/h2&gt;

&lt;p&gt;มี 2 รูปแบบ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"5"&lt;/li&gt;
&lt;li&gt;"05"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Year = 6
&lt;/h2&gt;

&lt;p&gt;มี 2 รูปแบบ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"2006"&lt;/li&gt;
&lt;li&gt;"06"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Time zone = 7
&lt;/h2&gt;

&lt;p&gt;ก่อนอื่นต้องทำความเข้าใจเรื่อง Time zone ก่อนว่าเราจะใช้มาตรฐาน UTC (Universal Time Coordinated) ซึ่งเป็นเวลาสากลเชิงพิกัด โดยจะใช้พิกัดเส้นลองจิจูด ที่ 0° เป็นจุดอ้างอิงว่าเป็น UTC-0 ซึ่งที่ตำแหน่งนั้น มันเป็นเส้นที่ตัดผ่านหอดูดาวหลวงกรีนิช ที่ลอนดอน ซึ่งแต่เดิมจะใช้เวลาจากหอดูดาวนี้ เป็นมาตรฐานเทียบเวลา เรียกว่า GTM (Greenwich Mean Time) แต่นั่นจะถือเป็นมาตรฐานเก่ากว่านะครับ เนื่องจากเป็นเวลาที่อ้างอิงตามหลักดาราศาสตร์ ปัจจุบันให้เปลี่ยนไปใช้ UTC ซึ่งอ้างอิงตามตำแหน่งพิกัดเส้นลองจิจูดแทน&lt;br&gt;
และยังมี MST (Mountain Standard Time) ซึ่งเป็นเวลาอ้างอิงเวลามาตรฐานกับเวลาที่เทือกเขาร็อกกี้ ซึ่งจะเท่ากับ UTC-7 พอดี ทำให้เราก็จะสามารถใช้ MST มาเป็นหนึ่งใน Format ของเราได้ด้วย&lt;/p&gt;

&lt;p&gt;มาดู format ของ time zone แบบเบื้องต้นที่ต้องการ parse time zone ในรูปแบบใช้เครื่องหมาย +/- ตามปกติกัน จะใช้รูปแบบนี้ คือต้องเป็น เครื่องหมายลบ "-" เท่านั้น และเลขต้องป็นเลข 7 เท่านั้น ซึ่งพอเอาไป parse เวลาจริง ถ้ามันจะมาเป็น +0800 ก็จะไปตรงกับ format "-0700" แต่ถ้าข้อมูลมาเป็น "+08" ก็ใช้ format "-07" เป็นต้น&lt;/p&gt;

&lt;p&gt;"-0700"     ±hhmm&lt;br&gt;
"-07:00"    ±hh:mm&lt;br&gt;
"-07"       ±hh&lt;br&gt;
"-070000"   ±hhmmss&lt;br&gt;
"-07:00:00" ±hh:mm:ss&lt;/p&gt;

&lt;p&gt;ต่อมาเป็นแบบ ISO 8601&lt;/p&gt;

&lt;p&gt;"Z0700"      Z or ±hhmm&lt;br&gt;
"Z07:00"     Z or ±hh:mm&lt;br&gt;
"Z07"        Z or ±hh&lt;br&gt;
"Z070000"    Z or ±hhmmss&lt;br&gt;
"Z07:00:00"  Z or ±hh:mm:ss&lt;/p&gt;

&lt;p&gt;ตัว Z หรือจะเรียกว่า Zulu ก็ได้ไม่ผิด เป็นสัญลักษณ์ที่ใช้วางไว้หลังเวลาวิธีใช้ก็แค่ใช้แทนเครื่องหมายลบ เท่านั้น เวลาแสดง format ก็จะมาในรูปแบบ +/- เหมือนเดิม&lt;/p&gt;

&lt;p&gt;MST ก็คือ time zone format เวลาที่เราต้องการ parse ตัว time zone ที่เป็นแบบระบุ time zone เช่น EST หรือ PST และแม้แต่จะ custom เองก็ได้เช่นกันผ่าน time.FixedZone&lt;/p&gt;

&lt;p&gt;เล่าไว้เท่านี้นะครับ สามารถอ่านให้ละเอียดมากกว่านี้ที่ &lt;a href="https://pkg.go.dev/time" rel="noopener noreferrer"&gt;https://pkg.go.dev/time&lt;/a&gt; และเพิ่มความเข้าใจผ่านการทดลองด้วยตัวเองดูจะดีกว่านะครับ&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
