Last active
March 14, 2021 16:39
-
-
Save guinso/55374e3193e1a4ad15f8df344f3789d3 to your computer and use it in GitHub Desktop.
Example hosting Golang web server where supporting both static file and dynamic request (REST)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
This web server serve 2 different type request: [static file] and [dynamic path] | |
[Static file] URL path: /* | |
[Dynamic Path] URL path: /api/* | |
Preparation: | |
1) Create "static-files" directory to place all static file like index.html | |
2) Create "dynamic-files" diectory to place all dynamic or hidden logical files, example invoice.pdf | |
3) Place "index.html" at root of "static-files" directory | |
4) Place "neon.jpg" (any kind of JPEG file) at root of "dynamic-files" directory | |
Sample URL: | |
1) http://localhost:7777/ - show static html file | |
2) http://localhost:7777/api/meals - demo GET Json request | |
3) http://localhost:7777/api/img/12345 - demo dynamic image request | |
**/ | |
package main | |
import ( | |
"fmt" | |
"io/ioutil" | |
"log" | |
"net/http" | |
"strings" | |
) | |
func main() { | |
// handler all request start from "/" | |
http.HandleFunc("/", handler) | |
// start HTTP server in socket 7777 | |
http.ListenAndServe(":7777", nil) | |
// start HTTPS server (default socket 443) | |
//x http.ListenAndServeTLS("/", "abc.crt", "abc.key", handler) | |
} | |
// Handle HTTP request to either static file server or REST server (URL start with "api/") | |
func handler(w http.ResponseWriter, r *http.Request) { | |
//remove first "/" character | |
urlPath := r.URL.Path[1:] | |
//if start with "api/" direct to REST handler | |
if strings.HasPrefix(urlPath, "api/") { | |
//trim prefix "api/" | |
trimmedURL := urlPath[4:] | |
/* | |
//trim suffix "/" | |
if strings.HasSuffix(trimmedURL, "/") { | |
trimmedURL = trimmedURL[0:(len(trimmedURL) - 1)] | |
} | |
*/ | |
routePath(w, r, trimmedURL) | |
} else { | |
log.Print("Entering static file handler: " + urlPath) | |
// define your static file directory | |
staticFilePath := "./static-files/" | |
//other wise, let read a file path and display to client | |
http.ServeFile(w, r, staticFilePath + urlPath) | |
} | |
} | |
//handle dynamic HTTP user requset | |
func routePath(w http.ResponseWriter, r *http.Request, trimURL string) { | |
// find and match trimmed URL to respective REST request | |
// trimmed URL | |
// request method | |
// input parameter(s) | |
if strings.HasPrefix(trimURL, "login") { | |
// example URL: localhost:7777/api/login | |
// TODO: handle login request | |
fmt.Fprint(w, "Request login") | |
} else if strings.HasPrefix(trimURL, "logout") { | |
// example URL: localhost:7777/api/logout | |
// TODO: handle logout request | |
fmt.Fprint(w, "Request logout") | |
} else if strings.HasPrefix(trimURL, "meals") { | |
// example URL: localhost:7777/api/meals | |
// show list of meals | |
w.Header().Set("Content-Type", "application/json") //MIME to application/json | |
w.WriteHeader(http.StatusOK) //status code 200, OK | |
w.Write([]byte("{ msg: \"this is meal A \" }")) //body text | |
} else if strings.HasPrefix(trimURL, "img/") { | |
// example URL: localhost:7777/api/img/ | |
// show image file to client dynamically | |
logicalFilePath := "./logic-files/" | |
physicalFileName := "neon.jpg" | |
// try read file | |
data, err := ioutil.ReadFile(logicalFilePath + physicalFileName) | |
if err != nil { | |
// show error page if failed to read file | |
handleErrorCode(500, "Unable to retrieve image file", w) | |
} else { | |
//w.Header().Set("Content-Type", "image/jpg") // #optional HTTP header info | |
// uncomment if image file is meant to download instead of display on web browser | |
// clientDisplayFileName = "customName.jpg" | |
//w.header().Set("Content-Disposition", "attachment; filename=\"" + clientDisplayFileName + "\"") | |
// write file (in binary format) direct into HTTP return content | |
w.Write(data) | |
} | |
} else { | |
// show error code 404 not found | |
handleErrorCode(404, "Path not found.", w) | |
} | |
} | |
// Generate error page | |
func handleErrorCode(errorCode int, description string, w http.ResponseWriter) { | |
w.WriteHeader(errorCode) // set HTTP status code (example 404, 500) | |
w.Header().Set("Content-Type", "text/html") // clarify return type (MIME) | |
w.Write([]byte(fmt.Sprintf( | |
"<html><body><h1>Error %d</h1><p>%s</p></body></html>", | |
errorCode, | |
description))) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Ty mate!