How to Upload Scanned Documents to a Go Server with Dynamic Web TWAIN

In the previous article, we demonstrated the implementation of a web application for scanning and uploading documents using Dynamic Web TWAIN and Node.js. In this article, we will guide you through achieving the same functionality using Go. The process closely mirrors the Node.js implementation, allowing you to reuse client-side resources and page files in your new project.

What you’ll build: A Go-based web server that serves a Dynamic Web TWAIN scanning page and receives uploaded document images via multipart form POST.

Key Takeaways

  • Dynamic Web TWAIN’s JavaScript frontend can pair with any HTTP backend — including Go — for document scanning and upload.
  • Go’s net/http and r.ParseMultipartForm handle the uploaded images in under 30 lines of code.
  • Client-side HTML/JS resources from a Node.js project can be reused as-is with a Go backend.
  • This approach works for any TWAIN-compatible scanner connected to the end user’s machine.

Common Developer Questions

How do I upload scanned documents from Dynamic Web TWAIN to a Golang server?

Create an /upload handler on the Go side and post the scanned file to it from the browser using Dynamic Web TWAIN’s upload API. The server then reads the multipart file stream and writes the uploaded image to disk.

Can I reuse the same Web TWAIN JavaScript frontend with different backend languages?

Yes. This article keeps the same client-side scanning page and only replaces the server-side upload endpoint, which is why the Node.js HTML and JavaScript can be reused with a Go backend.

How does Go parse multipart form data from a document scanner upload?

Call r.ParseMultipartForm(), iterate the uploaded RemoteFile entries, open each multipart file, and copy it into a server-side file handle with io.Copy(). That is enough to receive scanned images without adding a larger web framework.

Prerequisites

Build a Go Web Server for Document Upload

  1. Create a file named server.go.
  2. Within the file, import the necessary packages: fmt, io, net/http, and os.

     package main
    
     import (
     	"fmt"
     	"io"
     	"net/http"
     	"os"
     )
    
    • fmt is used for formatting and printing.
    • io provides the basic interfaces for I/O primitives.
    • net/http provides HTTP client and server implementations.
    • os provides a platform-independent interface to operating system functionality.
  3. Define the main function to configure and initiate the server.
     func main() {
     	http.HandleFunc("/", handFile) // loading Web resources
     	http.HandleFunc("/upload", uploadHandler) // receiving uploaded files
     	http.ListenAndServe(":2024", nil) // port number
     }
    
    • The function handFile loads the static web page index.html.
        func handFile(w http.ResponseWriter, r *http.Request) {
        	if (r.URL.Path == "/") {
        		http.ServeFile(w, r, "./index.html")
        	} else {
        		http.ServeFile(w, r, "." + r.URL.Path)
        	}
        }
      
    • The function uploadHandler receives uploaded images and saves them to the local disk. Compared to the Node.js implementation, the Go implementation is more concise and straightforward, thanks to the Go APIs that simplify the process of parsing multipart form data and saving the uploaded images to the local disk.

        func uploadHandler(w http.ResponseWriter, r *http.Request) {
        	err := r.ParseMultipartForm(2000)
        	if err != nil {
        		fmt.Fprintln(w, err)
        		return
        	}
              
        	formdata := r.MultipartForm
        	files := formdata.File["RemoteFile"]
        	for i := range files {
        		file, err := files[i].Open()
        		defer file.Close()
        		if err != nil {
        			fmt.Fprintln(w, err)
        			return
        		}
        		out, err := os.Create("UploadedImages/" + files[i].Filename)
        		defer out.Close()
        		if err != nil {
        			fmt.Fprintf(w, "create file err!")
        			return
        		}
        		_, err = io.Copy(out, file)
        		if err != nil {
        			fmt.Fprintln(w, err)
        			return
        		}
        	}
        }
      
    • 2024 is the designated port number.
  4. Run the server, then navigate to http://localhost:2024 in your web browser.

     go run server.go
    

    scan and upload documents with Dynamic Web TWAIN and Go

Reuse the Client-Side JavaScript Resources

The client-side resources, including the HTML file and JavaScript code, can be reused in the Go project. Simply copy the code from the previous article and integrate it into the HTML file.

The license key needs to be updated in the JavaScript code.

Dynamsoft.DWT.ProductKey = 'LICENSE-KEY';

Common Issues and Edge Cases

  • “UploadedImages” directory does not exist: The Go server will fail with a file-creation error if the UploadedImages/ folder is missing. Create it before starting the server, or add an os.MkdirAll("UploadedImages", 0755) call at startup.
  • Large file uploads rejected: The ParseMultipartForm(2000) call limits the in-memory portion to 2 KB. For multi-page PDF or high-resolution TIFF scans, increase this value (e.g., 32 << 20 for 32 MB) to avoid unexpected failures.
  • CORS errors when hosting frontend separately: If the scanning page is served from a different origin than the Go server, browsers will block the upload. Add CORS headers (Access-Control-Allow-Origin) to the Go handler or serve both from the same origin.

Source Code

Get the complete sample project source code on GitHub