Upload File

{{end}}

Perfect!

Now let’s go through the code in this file.

First, we have defined the template with the name upload, this is the name we will use to reference it later in our route handlers.

We then have some boilerplate HTML code in the head section, but I have included two important libraries here (well, just one is really important, the other is just for CSS vibes).

The HTMX library has been included with the

"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > HTMX 및 Golang을 사용한 파일 업로드

HTMX 및 Golang을 사용한 파일 업로드

2024-11-04에 게시됨
검색:494

Ofcourse you have already heard about the awesomeness of HTMX (you haven’t? well, good thing you’re here ?)

Today, we will be combining the simplicity of HTMX with the power of Golang to upload files to our server. Yeah, we are going to be building another exciting web feature with HTMX and Go.

By the way, if you really want a practical project-based guide on building fullstack apps with HTMX, check out my HTMX Go: Build Fullstack Applications with Golang and HTMX course [Discount Included].

So, let’s begin.

Setting Up the Go Project

The first step is to setup a simple Go project. We can do that by creating a folder, going into it and initialising it as a Go project using the commands below:

mkdir go-htmx-file-uploads
cd go-htmx-file-uploads
go mod init go-htmx-file-uploads

Once we have the project initialized, let’s now install some dependencies we will be requiring within our project.

This will be a simple server that will contain a single page with our upload form and also an endpoint that will be used to upload the file.

For routing, we will be using the Gorilla Mux routing library, but feel free to use any routing solution of your choice. We will also be using Google’s UUID library for Go to generate random names for our files when we upload them. This is a personal preference as you can generate file names in different ways.

Install these two with the commands below:

Gorillla Mux

go get -u github.com/gorilla/mux 

Google UUID

go get github.com/google/uuid

With these two installed, our project is fully set up, and we can move to the next step.

Creating our Templates

We will be creating two HTML templates for this little project.

The first template will be an HTML fragment that simply takes a slice of string messages that we can send from the server to the client.

This fragment will take this slice of messages and loop through it to create an HTML list to be returned to the client (remember how HTMX works with Hypermedia APIs, pretty cool huh ?).

So, let’s create that first.

At the root of the Go project, first create a templates folder inside which we will be storing all our templates.

Next, create a file messages.html inside the templates folder and add the following code to it:

{{define "messages"}}
    {{range .}}
  • {{ . }}
  • {{end}}
{{end}}

This defines a messages template and loops through the incoming slice of string messages to form an HTML list.

For our next template, we will be creating the file upload page itself.

Inside the templates folder, create a new file upload.html and paste in the code below:

{{define "upload"}}



    Upload File

Upload File

{{end}}

Perfect!

Now let’s go through the code in this file.

First, we have defined the template with the name upload, this is the name we will use to reference it later in our route handlers.

We then have some boilerplate HTML code in the head section, but I have included two important libraries here (well, just one is really important, the other is just for CSS vibes).

The HTMX library has been included with the

Then I have also brought in the Bootstrap CSS library, this is just to give our page elements some nice styling. It is not compulsory for this demo.

In the page itself, we have a form that does the upload. Let’s break down what is within the

tags.

First we have a

with an id of messages , this is the container where we will be loading all our server messages that come in as HTML. Remember the messages template, yeah, this is where the list of messages will be going into.

After that, we have the form input element that is set to file to ensure that it displays a file upload widget. We have given it the name avatar to reference it at the backend, but you can give this any name you want. I gave it avatar because i was using it to upload profile images.

Finally, we have the button which has been supercharged with HTMX. I have displayed it again below so we can go through it


First, I have added hx-post="/upload" , this tells it to submit the form to the /upload endpoint that we will be creating very soon and will handle the file upload.

Next is hx-encoding="multipart/form-data", this is compulsory for uploading files with HTMX to let the server know you’re sending along a file with the request.

Then we have hx-target="#messages" which tells the button to insert any response from the server into the

with an id of messages.

These three define our configuration for uploading the file to our backend.

Below is a preview of what our page looks like:

File Uploads with HTMX and Golang

Processing the File Upload

Now that we have our templates, it’s time to write the code that will display our upload page and also handle our file uploads.

To begin, at the root of the Go project, create a uploads folder. This is the folder where all our uploaded files will be stored.

With that in place, let’s write our main file.

Create the file main.go at the root of your project and add the following code:

package main

import (
    "html/template"
    "log"
    "net/http"
    "io"
    "os"
    "path/filepath"
    "github.com/google/uuid"
    "github.com/gorilla/mux"
)

var tmpl *template.Template

func init(){
    tmpl, _ = template.ParseGlob("templates/*.html")
}

func main() {


    router := mux.NewRouter()

    router.HandleFunc("/", homeHandler).Methods("GET")

    router.HandleFunc("/upload", UploadHandler).Methods("POST")

    log.Println("Server starting on :8080")
    log.Fatal(http.ListenAndServe(":8080", router))
}

func homeHandler(w http.ResponseWriter, r *http.Request) {

    tmpl.ExecuteTemplate(w, "upload", nil)

}

func UploadHandler(w http.ResponseWriter, r *http.Request) {


        // Initialize error messages slice
        var serverMessages []string

        // Parse the multipart form, 10 MB max upload size
        r.ParseMultipartForm(10  0 {
                tmpl.ExecuteTemplate(w, "messages", serverMessages)
                return
            }

        }
        defer file.Close()

        // Generate a unique filename to prevent overwriting and conflicts
        uuid, err := uuid.NewRandom()
        if err != nil {
            serverMessages = append(serverMessages, "Error generating unique identifier")
            tmpl.ExecuteTemplate(w, "messages", serverMessages)

            return
        }
        filename := uuid.String()   filepath.Ext(handler.Filename) // Append the file extension

        // Create the full path for saving the file
        filePath := filepath.Join("uploads", filename)

        // Save the file to the server
        dst, err := os.Create(filePath)
        if err != nil {
            serverMessages = append(serverMessages, "Error saving the file")
            tmpl.ExecuteTemplate(w, "messages", serverMessages)

            return
        }
        defer dst.Close()
        if _, err = io.Copy(dst, file); err != nil {
            serverMessages = append(serverMessages, "Error saving the file")
            tmpl.ExecuteTemplate(w, "messages", serverMessages)
            return
        }


        serverMessages = append(serverMessages, "File Successfully Saved")
        tmpl.ExecuteTemplate(w, "messages", serverMessages)


}

Yope, that’s a bunch of code. Don’t worry, we’ll go through it all step by step to figure out what this is all doing.

First we define our package main and import a bunch of libraries we will be making use of. These imports include the Gorilla mux router and the Google UUID library that we installed earlier.

After that, I create a global tmpl variable to hold all the HTML templates in the project and in the init() function, the templates are all loaded from the templates folder.

The main() Function

Now to the main() function. Here, we have initlialized the Gorilla Mux router and set up two routes.

The GET / base route which will be handled by a homeHandler function and displays our upload form, and the POST /upload route that will be handled by UploadHandler and handles the upload itself.

Finally, we print out a message to indicate that our server is running, and run the server on port 8080.

The Handler Functions

First we have homeHandler . This is the function that handles our base route, and it simply calls ExecuteTemplate on the tmpl variable with the name we gave to our template

tmpl.ExecuteTemplate(w, "upload", nil)

This call is enough to simply render our upload page to the screen when we visit the base route.

After that is the UploadHandler function. This is where the real magic happens, so let’s walk through the function.

First, we create a slice of strings called serverMessages to hold any message we want to send back to the client.

After that, we call ParseMultipartForm on the request pointer to limit the size of uploaded files to within 20MB.

r.ParseMultipartForm(10 



Next, we get a hold on our file by referencing the name of the file field with FormFile on the request pointer.

With our reference to the file, we check if there is actually a file, and if not, we return a message saying that no file was submitted or an error was encountered when trying to retrieve the file to account for other errors.

file, handler, err := r.FormFile("avatar")
        if err != nil {
            if err == http.ErrMissingFile {
                serverMessages = append(serverMessages, "No file submitted")
            } else {
                serverMessages = append(serverMessages, "Error retrieving the file")
            }

            if len(serverMessages) > 0 {
                tmpl.ExecuteTemplate(w, "messages", serverMessages)
                return
            }

        }

At this point, if our messages slice is not empty, we return the messages to the client and exit the function.

If a file is found, we keep the file open and move to generating a new name for it with the UUID library and also handle the errors in that process accordingly.

We build a new file name with the generated string and the file extension and set it’s path to the uploads folder.

    uuid, err := uuid.NewRandom()
        if err != nil {
            serverMessages = append(serverMessages, "Error generating unique identifier")
            tmpl.ExecuteTemplate(w, "messages", serverMessages)

            return
        }
        filename := uuid.String()   filepath.Ext(handler.Filename) 

        // Create the full path for saving the file
        filePath := filepath.Join("uploads", filename)

Once the new file path is constructed, we then use the os library to create the file path

After that, we use the io library to move the file from it’s temporary location to the new location and also handle errors accordingly.

    dst, err := os.Create(filePath)
        if err != nil {
            serverMessages = append(serverMessages, "Error saving the file")
            tmpl.ExecuteTemplate(w, "messages", serverMessages)

            return
        }
        defer dst.Close()
        if _, err = io.Copy(dst, file); err != nil {
            serverMessages = append(serverMessages, "Error saving the file")
            tmpl.ExecuteTemplate(w, "messages", serverMessages)
            return
        }

If we get no errors from the file saving process, we then return a successful message to the client using our messages template as we have done with previous messages.

serverMessages = append(serverMessages, "File Successfully Saved")
tmpl.ExecuteTemplate(w, "messages", serverMessages)

And that’s everything.

Now let’s take this code for a spin.

Testing the File Upload

Save the file and head over to the command line.

At the root of the project, use the command below to run our little file upload application:

go run main.go

Now go to your browser and head over to http://localhost:8080, you should see the upload screen displayed.

Try testing with no file to see the error message displayed. Then test with an actual file and also see that you get a successful message.

Check the uploads folder to confirm that the file is actually being saved there.

File Uploads with HTMX and Golang

And Wholla! You can now upload files to your Go servers using HTMX.

Conclusion

If you have enjoyed this article, and will like to learn more about building projects with HTMX, I’ll like you to check out HTMX Go: Build Fullstack Applications with Golang and HTMX, and The Complete HTMX Course: Zero to Pro with HTMX to further expand your knowledge on building hypermedia-driven applications with HTMX.

릴리스 선언문 이 기사는 https://dev.to/coderonfleek/file-uploads-with-htmx-and-golang-57ad?1에서 복제됩니다.1 침해 내용이 있는 경우, [email protected]에 연락하여 삭제하시기 바랍니다.
최신 튜토리얼 더>
  • Python만 사용하여 프런트엔드 구축
    Python만 사용하여 프런트엔드 구축
    프런트엔드 개발은 백엔드에 초점을 맞춘 개발자에게 벅차고 심지어 악몽 같은 작업이 될 수 있습니다. 내 경력 초기에는 프런트엔드와 백엔드 사이의 경계가 모호했고 모두가 두 가지를 모두 처리해야 했습니다. 특히 CSS는 끊임없는 투쟁이었습니다. 불가능한 임무처럼 느껴졌습...
    프로그램 작성 2024-11-05에 게시됨
  • Laravel에서 Cron 작업을 실행하는 방법
    Laravel에서 Cron 작업을 실행하는 방법
    이 튜토리얼에서는 Laravel에서 크론 작업을 실행하는 방법을 보여드리겠습니다. 무엇보다도 학생들을 위해 간단하고 쉽게 작업을 수행할 수 있습니다. Laravel 앱을 구축하는 동안 여러분의 컴퓨터에서 바로 이러한 자동화된 작업을 설정하고 실행하는 방법을 살펴보겠습니...
    프로그램 작성 2024-11-05에 게시됨
  • 패딩은 인라인 요소의 간격에 어떤 영향을 미치며 충돌을 어떻게 해결할 수 있습니까?
    패딩은 인라인 요소의 간격에 어떤 영향을 미치며 충돌을 어떻게 해결할 수 있습니까?
    인라인 요소의 패딩: 효과 및 제한소스에 따르면 인라인 요소의 상단과 하단에 패딩을 추가해도 영향을 미치지 않습니다. 주변 요소의 간격. 그러나 "패딩은 다른 인라인 요소와 겹칩니다"라는 설명은 패딩이 영향을 미치는 특정 상황이 있을 수 있음을 나타냅...
    프로그램 작성 2024-11-05에 게시됨
  • Django 클래스 기반 뷰가 쉬워졌습니다.
    Django 클래스 기반 뷰가 쉬워졌습니다.
    우리 모두 알고 있듯이 django는 웹 애플리케이션 개발 디자인에 MVT(모델-뷰-템플릿)를 사용합니다. 뷰 자체는 요청을 받고 응답을 반환하는 호출 가능 항목입니다. Django는 클래스 기반 뷰라는 것을 제공하므로 개발자는 클래스 기반 접근 방식을 사용하거나 O...
    프로그램 작성 2024-11-05에 게시됨
  • VAKX로 노코드 AI 에이전트 구축
    VAKX로 노코드 AI 에이전트 구축
    If you’ve been keeping up with the AI space, you already know that AI agents are becoming a game-changer in the world of automation and customer inter...
    프로그램 작성 2024-11-05에 게시됨
  • jQuery Datatable에서 커서 기반 페이지 매김을 구현하는 방법은 다음과 같습니다.
    jQuery Datatable에서 커서 기반 페이지 매김을 구현하는 방법은 다음과 같습니다.
    웹 애플리케이션에서 대규모 데이터세트로 작업할 때 페이지 매김은 성능과 사용자 경험에 매우 중요합니다. 데이터 테이블에 일반적으로 사용되는 표준 오프셋 기반 페이지 매김은 대규모 데이터 세트에는 비효율적일 수 있습니다. 커서 기반 페이지 매김은 특히 실시간 업데이트나...
    프로그램 작성 2024-11-05에 게시됨
  • 동기화 엔진이 웹 애플리케이션의 미래가 될 수 있는 이유
    동기화 엔진이 웹 애플리케이션의 미래가 될 수 있는 이유
    진화하는 웹 애플리케이션 세계에서는 효율성, 확장성, 원활한 실시간 경험이 무엇보다 중요합니다. 전통적인 웹 아키텍처는 응답성 및 동기화에 대한 현대적인 요구로 인해 어려움을 겪을 수 있는 클라이언트-서버 모델에 크게 의존합니다. 이것이 동기화 엔진이 등장하여 오늘날 ...
    프로그램 작성 2024-11-05에 게시됨
  • Python을 사용한 컴퓨터 비전 소개(1부)
    Python을 사용한 컴퓨터 비전 소개(1부)
    참고: 이 게시물에서는 쉽게 따라할 수 있도록 회색조 이미지만 사용합니다. 이미지란 무엇입니까? 이미지는 값의 행렬로 생각할 수 있으며, 각 값은 픽셀의 강도를 나타냅니다. 이미지 형식에는 세 가지 주요 유형이 있습니다. 이진: 이 형식의 이미지는 값이 ...
    프로그램 작성 2024-11-05에 게시됨
  • 웹사이트용 HTML 코드
    웹사이트용 HTML 코드
    항공 관련 웹사이트를 구축하려고 노력해왔습니다. 저는 AI를 사용하여 코드를 생성하는 전체 웹사이트를 생성할 수 있는지 확인하고 싶었습니다. HTML 웹사이트가 블로그와 호환됩니까, 아니면 자바스크립트를 사용해야 합니까? 데모로 사용한 코드는 다음과 같습니다. <...
    프로그램 작성 2024-11-05에 게시됨
  • 프로그래머처럼 생각하기: Java의 기본 사항 배우기
    프로그래머처럼 생각하기: Java의 기본 사항 배우기
    이 글에서는 자바 프로그래밍의 기본 개념과 구조를 소개합니다. 변수와 데이터 유형에 대한 소개로 시작한 다음 연산자와 표현식은 물론 제어 흐름 프로세스에 대해 논의합니다. 둘째, 메서드와 클래스를 설명하고 입력 및 출력 작업을 소개합니다. 마지막으로 이 기사에서는 급여...
    프로그램 작성 2024-11-05에 게시됨
  • PHP GD는 두 이미지의 유사성을 비교할 수 있나요?
    PHP GD는 두 이미지의 유사성을 비교할 수 있나요?
    PHP GD가 두 이미지의 유사성을 결정할 수 있습니까?고려 중인 질문은 두 이미지가 동일한지 확인하는 것이 가능한지 묻습니다. 차이점을 비교하여 PHP GD. 이는 두 이미지 간의 차이를 획득하고 그것이 완전히 흰색(또는 균일한 색상)으로 구성되어 있는지 결정하는 것...
    프로그램 작성 2024-11-05에 게시됨
  • 이 키를 사용하여 고급 수준 테스트 작성(JavaScript의 Test Desiderata)
    이 키를 사용하여 고급 수준 테스트 작성(JavaScript의 Test Desiderata)
    이 글에서는 모든 고위 개발자가 알아야 할 12가지 테스트 모범 사례를 배우게 됩니다. Kent Beck의 기사 "Test Desiderata"에 대한 실제 JavaScript 예제를 볼 수 있습니다. 그의 기사는 Ruby에 있기 때문입니다. 이러한 ...
    프로그램 작성 2024-11-05에 게시됨
  • matlab/octave 알고리즘을 C로 포팅하여 AEC에 대한 최상의 솔루션
    matlab/octave 알고리즘을 C로 포팅하여 AEC에 대한 최상의 솔루션
    완료! 나 자신에게 조금 감동받았습니다. 저희 제품에는 에코 제거 기능이 필요하며 세 가지 가능한 기술 솔루션이 확인되었습니다. 1) MCU를 사용하여 오디오 신호의 오디오 출력과 오디오를 감지하고 두 개의 선택적 채널 전환 사이의 오디오 출력과 오디오 입력의 강도에...
    프로그램 작성 2024-11-05에 게시됨
  • 단계별 웹 페이지 구축: HTML의 구조 및 요소 탐색
    단계별 웹 페이지 구축: HTML의 구조 및 요소 탐색
    ? 오늘은 내 소프트웨어 개발 여정의 중요한 단계입니다! ? 나는 첫 번째 코드 줄을 작성하여 HTML의 필수 요소를 살펴보았습니다. 해당 요소와 태그가 포함되어 있습니다. 어제는 웹사이트를 구성하는 복싱 기술을 탐구했고, 오늘은 머리글, 바닥글, 콘텐츠 영역과 같은 ...
    프로그램 작성 2024-11-05에 게시됨
  • 프로젝트 아이디어가 독특할 필요는 없습니다. 그 이유는 다음과 같습니다.
    프로젝트 아이디어가 독특할 필요는 없습니다. 그 이유는 다음과 같습니다.
    혁신의 세계에서는 프로젝트 아이디어가 가치를 가지려면 획기적이거나 완전히 독특해야 한다는 일반적인 오해가 있습니다. 그러나 그것은 사실과 거리가 멀다. 오늘날 우리가 사용하는 많은 성공적인 제품은 경쟁사와 핵심 기능 세트를 공유합니다. 이들을 차별화하는 것은 반드시 아...
    프로그램 작성 2024-11-05에 게시됨

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3