Intro
This time, I will try handling web requests.
I will use the project what I created last time.
Handling web requests
First I will try handling web requests.
Because I have never tried accessing database in Golang, I will try GET and POST methods in this time.
Separate operations by HTTP methods
Because "http.Handle" and "http.HandleFunc" don't have functions to specify the HTTP methods, I can't add same routes for each HTTP methods.
main.go
package main
import (
    "html/template"
    "log"
    "net/http"
    "path/filepath"
    "sync"
)
...
func main() {
...
    http.HandleFunc("/webrequest", webRequestHandler)
    // panic: http: multiple registrations for /webrequest
    http.HandleFunc("/webrequest", func(_ http.ResponseWriter, _ *http.Request) {
        log.Println("webrequest2")
    })
...
}
Therefore, I need to route requests for each HTTP method myself as follows.
main.go
...
func main() {
...
    http.HandleFunc("/webrequest", webRequestHandler)
...
}
webRequestSample.go
package main
import (
    "encoding/json"
    "errors"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)
func webRequestHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        // For GET request
        break
    case http.MethodPost:
        // For POST request
        break
    }
}
Get query paramters
I can get query paramters from "http.Request".
webRequestSample.go
...
func webRequestHandler(w http.ResponseWriter, r *http.Request) {
    name, err := getParam(r, "name")
    if err == nil {
        log.Println(name)
    } else {
        log.Println(err)
    }
...
}
func getParam(r *http.Request, key string) (string, error) {
    result := r.URL.Query().Get(key)
    if len(result) <= 0 {
        return "", errors.New(fmt.Sprintf("no value: %s", key))
    }
    return result, nil
}
- url package - net/url - pkg.go.dev
- net/http package get Query Params in Go(Golang) - Welcome to Golang by Example
Return formatted string values
webRequestSample.go
...
func webRequestHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        name, err := getParam(r, "name")
        if err != nil {
            fmt.Fprint(w, "The parameters have no names")
            return
        }
        fmt.Fprintf(w, "Hi there, I love %s!", name)
        break
...
    }
}
...
Return JSON values(+ reading values from body)
webRequest.page.ts
export function send() {
    fetch(targetUrl, 
        {
            method: "POST",
            body: JSON.stringify({ messageType: "text", data: "Hello" }),
        })
        .then(res => res.json())
        .then(json => console.log(json))
        .catch(err => console.error(err));
}
webRequestSample.go
...
type sampleResult struct {
    Message      string `json:"message"`
    Succeeded    bool   `json:"succeeded"`
    ErrorMessage string `json:"errorMessage"`
}
func webRequestHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
...
    case http.MethodPost:
        returnValue := &sampleResult{}
        w.Header().Set("Content-Type", "application/json")
        // read values from HTTP request body
        body, readBodyError := ioutil.ReadAll(r.Body)
        if readBodyError != nil {
            returnValue.Succeeded = false
            returnValue.ErrorMessage = "Failed reading values from body"
            failedReadingData, _ := json.Marshal(returnValue)
            w.Write(failedReadingData)
            return
        }
        wsMessage := &websocketMessage{}
        convertError := json.Unmarshal(body, &wsMessage)
        if convertError != nil {
            returnValue.Succeeded = false
            returnValue.ErrorMessage = "Failed converting to WebSocketMessage"
            failedConvertingData, _ := json.Marshal(returnValue)
            w.Write(failedConvertingData)
            return
        }
        w.WriteHeader(200)
        returnValue.Message = fmt.Sprintf("%s_1", wsMessage.Data)
        returnValue.Succeeded = true
        returnValue.name = "hello world"
        data, _ := json.Marshal(returnValue)
        w.Write(data)
        break
    }
}
...
Result
{
    "message": "Hello_1",
    "succeeded": true,
    "errorMessage": ""
}
structs for json.Marshal & json.Unmarshal
I defined "sampleResult" like below.
type sampleResult struct {
    message      string
    succeeded    bool
    errorMessage string
}
Because "json.Marshal" and "json.Unmarshal" ignore private properties, the results always became empty values :P
- json package - encoding/json - pkg.go.dev
- Return JSON body in HTTP response in Go (Golang) - Welcome To Golang By Example
Return file data
webRequestSample.go
...
func webRequestHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        name, err := getParam(r, "name")
        if err != nil {
            log.Println(err.Error())
            return
        }
        // Search file from current directory
        cur, _ := os.Getwd()
        file, fileErr := os.Open(fmt.Sprintf("%s/files/%s", cur, name))
        if fileErr != nil {
            log.Println(fileErr.Error())
            w.WriteHeader(404)
            return
        }
        // Get file infomations
        fileinfo, staterr := file.Stat()
        if staterr != nil {
            log.Println(staterr.Error())
            w.WriteHeader(404)
            return
        }
        // To download file, I set "application/octet-stream" as Content-Type
        w.Header().Set("Content-Type", "application/octet-stream")
        // set its file name
        cd := mime.FormatMediaType("attachment", map[string]string{"filename": fileinfo.Name()})
        w.Header().Set("Content-Disposition", cd)
        http.ServeContent(w, r, fileinfo.Name(), fileinfo.ModTime(), file)
        break
...
File name
First, I tried reading the file and return byte array like below.
...
        // Get file infomations
        fileinfo, staterr := file.Stat()
        if staterr != nil {
            log.Println(staterr.Error())
            w.WriteHeader(404)
            return
        }
        // Read file
        fileData := make([]byte, fileinfo.Size())
        fileSize, loadErr := file.Read(fileData)
        if loadErr != nil {
            log.Println(loadErr.Error())
            w.WriteHeader(404)
            return
        }
        // To download file, I set "application/octet-stream" as Content-Type
        w.Header().Set("Content-Type", "application/octet-stream")
        w.Write(fileData)
        break
...
But the downloaded files were always named like "webrequest", so I changed to use "http.ServeContent".
 

 
    
Top comments (0)