Introduction#
- S3 client
- Bedrock client
- PostgreSQL and GORM as an ORM
- PostgreSQL pure driver pq
S3 Client#
- Upload a file to S3
- List bucket
First let create a S3 client
var client *s3.Clientfunc init () {config, error := config.LoadDefaultConfig(context.TODO())if error != nil {fmt.Println("ERROR")}client = s3.NewFromConfig(config)}
Let call an api to list bucket
func listBuckets() {result, error := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})if error != nil {fmt.Println("ERROR")}for _, bucket := range result.Buckets {fmt.Println(*bucket.Name)}}
Or upload an object to S3
resp, error := client.PutObject(context.TODO(),&s3.PutObjectInput{Bucket: aws.String("cdk-entest-videos"),Key: aws.String("golang.jpeg"),Body: bytes.NewReader(data),},)
This is the full example
main.go
package mainimport ("bytes""context""fmt""os""github.com/aws/aws-sdk-go-v2/aws""github.com/aws/aws-sdk-go-v2/config""github.com/aws/aws-sdk-go-v2/service/s3")var client *s3.Clientfunc init () {config, error := config.LoadDefaultConfig(context.TODO())if error != nil {fmt.Println("ERROR")}client = s3.NewFromConfig(config)}func listBuckets() {result, error := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})if error != nil {fmt.Println("ERROR")}for _, bucket := range result.Buckets {fmt.Println(*bucket.Name)}}func main() {data, error := os.ReadFile("dolphin.jpeg")if error != nil {fmt.Println("ERROR")}resp, error := client.PutObject(context.TODO(),&s3.PutObjectInput{Bucket: aws.String("cdk-entest-videos"),Key: aws.String("golang.jpeg"),Body: bytes.NewReader(data),},)if error != nil {fmt.Println("ERROR")}fmt.Println(resp)}
Bedrock Client#
First let define struct for Request and Response
type Request struct {Prompt string `json:"prompt"`MaxTokensToSample int `json:"max_tokens_to_sample"`Temperature float64 `json:"temperature,omitempty"`TopP float64 `json:"top_p,omitempty"`TopK int `json:"top_k,omitempty"`StopSequences []string `json:"stop_sequences,omitempty"`}type Response struct {Completion string `json:"completion"`}type HelloHandler struct{}
Then, let create a bedrock client
// promt formatconst claudePromptFormat = "\n\nHuman: %s\n\nAssistant:"// bedrock runtime clientvar brc *bedrockruntime.Client// init bedorck credentials connecting to awsfunc init() {region := os.Getenv("AWS_REGION")if region == "" {region = "us-east-1"}cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(region))if err != nil {log.Fatal(err)}brc = bedrockruntime.NewFromConfig(cfg)}
Let call a request with streaming response
func bedrock() {prompt := "" + fmt.Sprintf(claudePromptFormat, "How to cook chicken soup?")payload := Request{Prompt: prompt,MaxTokensToSample: 2048,}payloadBytes, error := json.Marshal(payload)if error != nil {fmt.Println(error)}output, error := brc.InvokeModelWithResponseStream(context.Background(),&bedrockruntime.InvokeModelWithResponseStreamInput{Body: payloadBytes,ModelId: aws.String("anthropic.claude-v2"),ContentType: aws.String("application/json"),},)if error != nil {fmt.Println(error)}for event := range output.GetStream().Events() {switch v := event.(type) {case *types.ResponseStreamMemberChunk:var resp Responseerr := json.NewDecoder(bytes.NewReader(v.Value.Bytes)).Decode(&resp)if err != nil {fmt.Println(err)}fmt.Println(resp.Completion)case *types.UnknownUnionMember:fmt.Println("unknown tag:", v.Tag)default:fmt.Println("union is nil or unknown type")}}}
This is the full example
main.go
package mainimport ("bytes""context""encoding/json""fmt""log""os""github.com/aws/aws-sdk-go-v2/aws""github.com/aws/aws-sdk-go-v2/config""github.com/aws/aws-sdk-go-v2/service/bedrockruntime""github.com/aws/aws-sdk-go-v2/service/bedrockruntime/types")type Request struct {Prompt string `json:"prompt"`MaxTokensToSample int `json:"max_tokens_to_sample"`Temperature float64 `json:"temperature,omitempty"`TopP float64 `json:"top_p,omitempty"`TopK int `json:"top_k,omitempty"`StopSequences []string `json:"stop_sequences,omitempty"`}type Response struct {Completion string `json:"completion"`}// promt formatconst claudePromptFormat = "\n\nHuman: %s\n\nAssistant:"// bedrock runtime clientvar brc *bedrockruntime.Client// init bedorck credentials connecting to awsfunc init() {region := os.Getenv("AWS_REGION")if region == "" {region = "us-east-1"}cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(region))if err != nil {log.Fatal(err)}brc = bedrockruntime.NewFromConfig(cfg)}func main() {fmt.Println("Hello Bedrock")bedrock()}func bedrock() {prompt := "" + fmt.Sprintf(claudePromptFormat, "How to cook chicken soup?")payload := Request{Prompt: prompt,MaxTokensToSample: 2048,}payloadBytes, error := json.Marshal(payload)if error != nil {fmt.Println(error)}output, error := brc.InvokeModelWithResponseStream(context.Background(),&bedrockruntime.InvokeModelWithResponseStreamInput{Body: payloadBytes,ModelId: aws.String("anthropic.claude-v2"),ContentType: aws.String("application/json"),},)if error != nil {fmt.Println(error)}for event := range output.GetStream().Events() {switch v := event.(type) {case *types.ResponseStreamMemberChunk:var resp Responseerr := json.NewDecoder(bytes.NewReader(v.Value.Bytes)).Decode(&resp)if err != nil {fmt.Println(err)}fmt.Println(resp.Completion)case *types.UnknownUnionMember:fmt.Println("unknown tag:", v.Tag)default:fmt.Println("union is nil or unknown type")}}}
Gorm PostgreSQL#
- Create a db connection
- Query an existing table
- Create model, table, CRUD
First let create a database connection
const HOST = "const USER = "postgresql"const DBNAME = "demo"const PASS = ""dsn := fmt.Sprintf("host=%v port=%v user=%v password=%v dbname=%v", HOST, "5432", USER, PASS, DBNAME)db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{NamingStrategy: schema.NamingStrategy{NoLowerCase: false,SingularTable: true,},})
Second, assume that there is already an existing table named Actor, let query it. We need to specify table name.
[!IMPORTANT] Please check the syntax for table and column name, first character should be cap.
type Actor struct {Actor_id string `gorm:"PrimaryKey"`First_name stringLast_name stringLast_update string}type Tabler interface {TableName() string}func (Actor) TableName() string {return "actor"}
Then let query Actor table
func getActors(db *gorm.DB) {var actors []Actordb.Limit(2).Find(&actors)for _, actor := range actors {fmt.Println(actor.Actor_id)fmt.Printf(actor.First_name)fmt.Println(actor.Last_name)fmt.Println(actor.Last_update)}var actor Actordb.First(&actor)fmt.Println(actor.Actor_id)fmt.Printf(actor.First_name)fmt.Println(actor.Last_name)fmt.Println(actor.Last_update)}
Create a new model named Book
type Book struct {ID uintTitle stringAuthor stringAmazon stringImage stringDescription string}
Then create function to do CRUP
// create tablefunc createTable(db *gorm.DB) {db.AutoMigrate(&Book{})}// read datafunc readTable(db *gorm.DB) {var books []Bookdb.Limit(10).Find(&books)for _, book := range books {fmt.Println(book.Author+", ", book.Title)}}// insert datafunc insertData(db *gorm.DB) {db.Create(&Book{Title: "Database Internals",Author: "Hai Tran",Amazon: "",Description: "Hello",Image: "",})}// update datafunc updateData(db *gorm.DB) {db.Model(&Book{}).Where("id = ?", "2").Update("Image", "golang-idiomatic.jpeg")}// delete rowfunc deleteRows(db *gorm.DB) {// delete book where id=5// db.Delete(&Book{}, 4)var books []Bookdb.Delete(&books, []int{1})}
Here is the full example
main.go
// haimtran 08/01/2024// getting started with golang gorm orm// psql -h database-1.c9y4mg20eppz.ap-southeast-1.rds.amazonaws.com -p 5432 -U postgresql -d demopackage mainimport ("fmt""gorm.io/driver/postgres""gorm.io/gorm""gorm.io/gorm/schema")type Actor struct {Actor_id string `gorm:"PrimaryKey"`First_name stringLast_name stringLast_update string}type Tabler interface {TableName() string}func (Actor) TableName() string {return "actor"}type Book struct {ID uintTitle stringAuthor stringAmazon stringImage stringDescription string}// create tablefunc createTable(db *gorm.DB) {db.AutoMigrate(&Book{})}// delete rowfunc deleteRows(db *gorm.DB) {// delete book where id=5// db.Delete(&Book{}, 4)var books []Bookdb.Delete(&books, []int{1})}// insert datafunc insertData(db *gorm.DB) {db.Create(&Book{Title: "Database Internals",Author: "Hai Tran",Amazon: "",Description: "Hello",Image: "",})}// update datafunc updateData(db *gorm.DB) {db.Model(&Book{}).Where("id = ?", "2").Update("Image", "golang-idiomatic.jpeg")}// read datafunc readTable(db *gorm.DB) {var books []Bookdb.Limit(10).Find(&books)for _, book := range books {fmt.Println(book.Author+", ", book.Title)}}// read tablefunc getActors(db *gorm.DB) {var actors []Actordb.Limit(2).Find(&actors)for _, actor := range actors {fmt.Println(actor.Actor_id)fmt.Printf(actor.First_name)fmt.Println(actor.Last_name)fmt.Println(actor.Last_update)}var actor Actordb.First(&actor)fmt.Println(actor.Actor_id)fmt.Printf(actor.First_name)fmt.Println(actor.Last_name)fmt.Println(actor.Last_update)}const HOST = "database-1.c9y4mg20eppz.ap-southeast-1.rds.amazonaws.com"const USER = "postgresql"const DBNAME = "demo"const PASS = "Admin2024"func main() {dsn := fmt.Sprintf("host=%v port=%v user=%v password=%v dbname=%v", HOST, "5432", USER, PASS, DBNAME)db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{NamingStrategy: schema.NamingStrategy{NoLowerCase: false,SingularTable: true,},})if err != nil {fmt.Println("ERROR")}// getActors(db)// createTable(db)insertData(db)// readTable(db)// updateData(db)// deleteRows(db)}
PostgreSQL Driver#
Let use a pure driver to send query to database
func getBooks(db *sql.DB) []Book {rows, error := db.Query("SELECT * FROM book LIMIT 10;")if error != nil {log.Fatal(error)}// wait untill all surrouding functions finish and run rows.Close()defer rows.Close()var books []Bookfor rows.Next() {var book Bookif error := rows.Scan(&book.ID, &book.Title, &book.Author, &book.Description, &book.Image, &book.Amazon); error != nil {fmt.Println(error)}fmt.Print(book)books = append(books, book)}fmt.Println(books)return books}
Here is the full code
main.go
package mainimport ("database/sql""fmt""log"_ "github.com/lib/pq")type Actor struct {actor_id intfirst_name stringlast_name stringlast_update string}type Book struct {ID uintAuthor stringTitle stringImage stringDescription stringAmazon string}func main() {fmt.Println("Hello")connStr := "host=localhost port=5432 user=demo dbname=dvdrental password='Mike@865525' sslmode=disable"db, error := sql.Open("postgres", connStr)if error != nil {log.Fatal(error)}rows, error := db.Query("SELECT * FROM actor LIMIT 10;")if error != nil {log.Fatal(error)}// wait untill all surrouding functions finish and run rows.Close()defer rows.Close()var actors []Actorfor rows.Next() {var actor Actorif err := rows.Scan(&actor.actor_id, &actor.first_name, &actor.last_name, &actor.last_update); err != nil {fmt.Println(err)}fmt.Println(actor)actors = append(actors, actor)}fmt.Println(actors)//getBooks(db)}func getBooks(db *sql.DB) []Book {rows, error := db.Query("SELECT * FROM book LIMIT 10;")if error != nil {log.Fatal(error)}// wait untill all surrouding functions finish and run rows.Close()defer rows.Close()var books []Bookfor rows.Next() {var book Bookif error := rows.Scan(&book.ID, &book.Title, &book.Author, &book.Description, &book.Image, &book.Amazon); error != nil {fmt.Println(error)}fmt.Print(book)books = append(books, book)}fmt.Println(books)return books}
HTTP Server#
- Create web server
- Create multiplexer and handlers
- Serve static file
- Response json
- Upload file
Let create a http server listening on port 3000
server := &http.Server{Addr: ":3000",Handler: mux,ReadTimeout: 10 * time.Second,WriteTimeout: 10 * time.Second,MaxHeaderBytes: 1 << 20,}log.Fatal(server.ListenAndServe())
Create multiplexer and handlers
mux := http.NewServeMux()mux.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) {data := showBooks()w.Header().Set("Content-Type", "application/json")w.Write(data)})mux.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {switch r.Method {case "GET":http.ServeFile(w, r, "upload.html")case "POST":uploadFile(w, r)}})
Upload file handler
func uploadFile(w http.ResponseWriter, r *http.Request) {// maximum upload file of 10 MB filesr.ParseMultipartForm(10 << 20)// Get handler for filename, size and heandersfile, handler, error := r.FormFile("myFile")if error != nil {fmt.Println("Error")fmt.Println(error)return}defer file.Close()fmt.Printf("upload file %v\n", handler.Filename)fmt.Printf("file size %v\n", handler.Size)fmt.Printf("MIME header %v\n", handler.Header)// Create filedest, error := os.Create(handler.Filename)if error != nil {return}defer dest.Close()// Copy uploaded file to destif _, err := io.Copy(dest, file); err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}fmt.Fprintf(w, "Successfully Uploaded File\n")}
Show books logic
func showBooks() []byte {book := Book{ID: 1,Title: "Golang",Author: "Hai",Description: "Hello",Amazon: "",Image: "",}// encode to []bytejs, error := json.Marshal(book)if error != nil {log.Fatal(error)}fmt.Println(js)// decode bytesvar x Bookjson.Unmarshal(js, &x)fmt.Println(x)return js}
This is full code
go.main
package mainimport ("encoding/json""fmt""io""log""net/http""os""time")type Book struct {ID uintAuthor stringTitle stringImage stringDescription stringAmazon string}func main() {mux := http.NewServeMux()mux.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) {data := showBooks()w.Header().Set("Content-Type", "application/json")w.Write(data)})mux.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {switch r.Method {case "GET":http.ServeFile(w, r, "upload.html")case "POST":uploadFile(w, r)}})// create serverserver := &http.Server{Addr: ":3000",Handler: mux,ReadTimeout: 10 * time.Second,WriteTimeout: 10 * time.Second,MaxHeaderBytes: 1 << 20,}log.Fatal(server.ListenAndServe())}func uploadFile(w http.ResponseWriter, r *http.Request) {// maximum upload file of 10 MB filesr.ParseMultipartForm(10 << 20)// Get handler for filename, size and heandersfile, handler, error := r.FormFile("myFile")if error != nil {fmt.Println("Error")fmt.Println(error)return}defer file.Close()fmt.Printf("upload file %v\n", handler.Filename)fmt.Printf("file size %v\n", handler.Size)fmt.Printf("MIME header %v\n", handler.Header)// Create filedest, error := os.Create(handler.Filename)if error != nil {return}defer dest.Close()// Copy uploaded file to destif _, err := io.Copy(dest, file); err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}fmt.Fprintf(w, "Successfully Uploaded File\n")}func showBooks() []byte {book := Book{ID: 1,Title: "Golang",Author: "Hai",Description: "Hello",Amazon: "",Image: "",}// encode to []bytejs, error := json.Marshal(book)if error != nil {log.Fatal(error)}fmt.Println(js)// decode bytesvar x Bookjson.Unmarshal(js, &x)fmt.Println(x)return js}
Echo Framework#
- Create a web server
- Handle upload file
- Handle simple get request
// haimtran 07/01/2024// echo webserver get, post, form, uploadpackage mainimport ("context""fmt""io""net/http""os""github.com/aws/aws-sdk-go-v2/aws""github.com/aws/aws-sdk-go-v2/config""github.com/aws/aws-sdk-go-v2/service/s3""github.com/labstack/echo/v4")var client *s3.Clientfunc init () {config, error := config.LoadDefaultConfig(context.TODO())if error != nil {fmt.Println("ERROR")}client = s3.NewFromConfig(config)}func main() {e := echo.New()e.GET("/", func(c echo.Context) error {return c.String(http.StatusOK, "Hello Hai")})// path parametere.GET("/user/:id", func(c echo.Context) error {id := c.Param("id")return c.String(http.StatusOK, id)})// query parametere.GET("/show", func(c echo.Context) error {name := c.QueryParam("name")return c.String(http.StatusOK, "hello: " + name)})// form// curl -d "name=hai" -d "email=minh@gmail.com" http://localhost:3000/savee.POST("/save", func(c echo.Context) error {name := c.FormValue("name")email := c.FormValue("email")return c.String(http.StatusOK, "name: " + name + "email: " + email)})// curl -F "name=Joe Smith" -F "avatar=dolphin.jpeg" http://localhost:3000/uploade.POST("/upload", func(c echo.Context) error {// get namename := c.FormValue("name")// get avataravatar, error := c.FormFile("avatar")if error != nil {return error}// sourcesrc, error := avatar.Open()if error != nil {return error}defer src.Close()// destinationdest, error := os.Create(avatar.Filename)if error != nil {return error}defer dest.Close()// upload file to s3_, error = client.PutObject(context.TODO(), &s3.PutObjectInput{Bucket: aws.String("cdk-entest-videos"),Key: aws.String("golang/dolphin.jpeg"),Body: src,})if error != nil {fmt.Println("error upload to s3")}// copyif _, error = io.Copy(dest, src); error != nil {return error}return c.HTML(http.StatusOK,"<b>Thank you! " + name + "</b>",)})e.Logger.Fatal(e.Start(":3000"))}
Encoding Json#
- Encode to byte array
- Decode byte array to string
- Json Ecoder and Decoder
package mainimport ("encoding/json""fmt""log")type Book struct {ID uintAuthor stringTitle stringImage stringDescription stringAmazon string}func main() {fmt.Println("HELLO")showBooks()}func showBooks() {book := Book{ID: 1,Title: "Golang",Author: "Hai",Description: "Hello",Amazon: "",Image: "",}// encode to []bytejs, error := json.Marshal(book)if error != nil {log.Fatal(error)}fmt.Println(js)// decode bytesvar x Bookjson.Unmarshal(js, &x)fmt.Println(x)}
Let use json encoder and decoder to parse request and stream response to client. For example, a simple json encoder to write to response
json.NewEncoder(w).Encode(map[string]interface{}{"Result": string(respBytes)})
And simple json decoder to parse request from frontend client
// data struct of requestvar request struct {Query string `json:"query"`}// parse user query from requestvar query stringerror := json.NewDecoder(r.Body).Decode(&request)
And this is full code
func HandleAOSSQueryByTitle(w http.ResponseWriter, r *http.Request, AOSSClient *opensearch.Client, BedrockClient *bedrockruntime.Client) {// data struct of requestvar request struct {Query string `json:"query"`}// parse user query from requestvar query stringerror := json.NewDecoder(r.Body).Decode(&request)if error != nil {fmt.Println(error)}query = request.Queryfmt.Println(query)// query opensearh match by titleresponse, error := QueryOpenSearchByTitle(AOSSClient, query)if error != nil {fmt.Println(error)}respBytes, err := io.ReadAll(response.Body)if err != nil {panic(err)}// fmt.Println(string(respBytes))// write answer to responsejson.NewEncoder(w).Encode(map[string]interface{}{"Result": string(respBytes)})}
Interface Method#
Interface is a set of method
// haimtran 07/01/2024// method on type// interface as a step of methodpackage mainimport ("fmt")// method on typetype Abser struct{}// implement method on typefunc (hh Abser) Abs() string {fmt.Println("abs method implemented")return "Hello"}// a set of method signaturetype Demo interface {SayHello(message string)SayHi()}// method on typetype MyHello struct {}// implement method 1 on typefunc (hh MyHello) SayHello(message string) {fmt.Printf("say hello %v\n", message)}// implement method 2 on typefunc (hh MyHello) SayHi() {fmt.Println("say hi")}func main() {fmt.Println("Hello")var x Abserx.Abs()var a Demof := MyHello{}a = fa.SayHello("HEHEHE")a.SayHi()}
Upload File#
- create simple frontend form
- backend handler
- how to parse the form data
Let create a simple frontend form to upload. There are two options
- upload using form
- upload using javascript
Here the script to upload via form data
// formdataconst formData = new FormData()formData.append('name', 'Hai')formData.append('file', file)console.log(formData)try {await fetch('/cv-backend', {method: 'POST',body: formData})} catch (error) {console.log(error)}
Here is the detail frontend code
upload.html
<html><head><title>Upload PDF</title><meta name="viewport" content="width=device-width" /><style>:root {box-sizing: border-box;}*,::before,::after {box-sizing: inherit;}body {background-color: antiquewhite;}.container {max-width: 500px;margin: auto;}.container-form {position: relative;}.input-question {width: 100%;padding: 15px 10px;}.button-submit {background-color: orange;padding: 10px 25px;border-radius: 2px;border: none;outline: none;position: absolute;top: 50%;right: 10px;transform: translateY(-50%);cursor: pointer;}.input-file {width: 100%;padding: 15px 10px;background-color: aquamarine;cursor: pointer;margin-top: 10px;}.container-image {position: relative;background-color: gainsboro;padding: 10px 10px;align-items: center;justify-content: center;display: flex;max-height: 600px;height: 50%;}.description-image {position: absolute;bottom: 0;left: 0;background-color: azure;padding: 10px;opacity: 0.9;}</style></head><body><div class="container"><div><form onkeydown="return event.key != 'Enter';"><div class="container-form"><inputtype="text"id="question"name="question"class="input-question"placeholder="what is in this image?"/><button class="button-submit" id="submit" type="submit">Upload</button></div><input type="file" id="file" name="file" class="input-file" /></form></div></div></body><script>const fileInput = document.getElementById('file')const submit = document.getElementById('submit')let file// get filefileInput.addEventListener('change', event => {// get filefile = event.target.files[0]if (file) {console.log(file)}})// cal backend cv endpointconst summaryCV = async () => {// get user promptlet question = document.getElementById('question').valueif ((question == '') | (question == null)) {question = 'what is in this image?'}// formdataconst formData = new FormData()formData.append('name', 'Hai')formData.append('file', file)console.log(formData)try {await fetch('/cv-backend', {method: 'POST',body: formData})} catch (error) {console.log(error)}}submit.addEventListener('click', async event => {event.preventDefault()await summaryCV()})// listen on enterdocument.getElementById('question').addEventListener('keydown', async event => {if (event.code === 'Enter') {await summaryCV()}})</script></html>
Write a simple backend handler to save the uploaded data
package bedrockimport ("encoding/json""fmt""io""net/http""os")func HandleCV(w http.ResponseWriter, r *http.Request) {error := r.ParseMultipartForm(32 << 20)if error != nil {fmt.Println(error)}// parse parametersfmt.Println(r.PostForm.Get("name"))// parse filefile, header, error := r.FormFile("file")if error != nil {fmt.Println(error)}fmt.Println(header.Filename)// create file in diskdest, error := os.Create(header.Filename)if error != nil {fmt.Println(error)}// write file to diskio.Copy(dest, file)json.NewEncoder(w).Encode("hello")}
Write a simple http server
// handle cv frontendmux.HandleFunc("/cv", func(w http.ResponseWriter, r *http.Request) {http.ServeFile(w, r, "./static/cv.html")})// handle cv backendmux.HandleFunc("/cv-backend", func(w http.ResponseWriter, r *http.Request) {if r.Method == "POST" {gobedrock.HandleCV(w, r)}})// allow corshandler := cors.AllowAll().Handler(mux)// create a http server using httpserver := http.Server{Addr: ":3000",Handler: handler,ReadTimeout: 30 * time.Second,WriteTimeout: 30 * time.Second,MaxHeaderBytes: 1 << 20,}server.ListenAndServe()
Full backend code
main.go
package mainimport ("encoding/json""fmt""io""net/http""os""time""github.com/rs/cors")func HandleCV(w http.ResponseWriter, r \*http.Request) {error := r.ParseMultipartForm(32 << 20)if error != nil {fmt.Println(error)}// parse parametersfmt.Println(r.PostForm.Get("name"))// parse filefile, header, error := r.FormFile("file")if error != nil {fmt.Println(error)}fmt.Println(header.Filename)// create file in diskdest, error := os.Create(header.Filename)if error != nil {fmt.Println(error)}// write file to diskio.Copy(dest, file)json.NewEncoder(w).Encode("hello")}func main() {mux := http.NewServeMux()// handle cv frontendmux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {http.ServeFile(w, r, "upload.html")})// handle cv backendmux.HandleFunc("/upload-backend", func(w http.ResponseWriter, r *http.Request) {if r.Method == "POST" {HandleCV(w, r)}})// allow corshandler := cors.AllowAll().Handler(mux)// create a http server using httpserver := http.Server{Addr: ":3000",Handler: handler,ReadTimeout: 30 * time.Second,WriteTimeout: 30 * time.Second,MaxHeaderBytes: 1 << 20,}server.ListenAndServe()}