首页 > 其他分享 >[Go] A simple Go server

[Go] A simple Go server

时间:2024-02-09 16:11:40浏览次数:27  
标签:http err simple server api func Go data

Hello World

Let's create a simple Go server, first let's setup the server and do hello world

// @filename: main.go
package main

import (
	"fmt"
	"net/http"
)

func handleHello (res http.ResponseWriter, req *http.Request) {
    // Covert to []bytpe type
	res.Write([]byte("Hello from a Go program"))
}

func main {
    server := http.NewServeMux()
    server.HandleFunc("/hello", handleHello)
    
    err := http.ListenAndServe(":3333", server)
    if err != nil {
        fmt.Println("Server cannot start")
    }
}

After run go run ., you can visit localhost:3333/helloto see the server is running and return hello world.

 

Static HTML

Now let's serve a static HTML, let say we have a publicfolder with an index.htmlfile inside.

We want to serve the public files on our serve

// @filename: main.go
package main

import (
	"fmt"
	"net/http"
)

func handleHello (res http.ResponseWriter, req *http.Request) {
    // Covert to []bytpe type
	res.Write([]byte("Hello from a Go program"))
}

func main {
    server := http.NewServeMux()
    server.HandleFunc("/hello", handleHello)
    
    // Serve public files
    fs := http.FileServer(http.Dir("./public"))
    server.Handle("/", fs)
    
    err := http.ListenAndServe(":3333", server)
    if err != nil {
        fmt.Println("Server cannot start")
    }
}

Rerun the server, visit localhost:3333you should be able to see the index.html file

 

Data Layer

// @filename: data/exhibitions.go

package data

type Exhibition struct {
	Title string
	Description string
	Image string
	CurrentlyOpened bool
}

var list = []Exhibition{
	{
		Title:       "Life in Ancient Greek",
		Description: "Uncover the world of ancient Greece through the sculptures, tools, and jewelry found in ruins from over 2000 years ago that have been unearthed through modern science and technology.",
		Image:       "ancient-greece.png",
		CurrentlyOpened: false,
	},
	{
		Title:       "Aristotle: Life and Legacy",
		Description: "Explore the life and legacy of the great philosopher Aristotle, one of the most influential thinkers of all time. Through rare artifacts and ancient texts, learn about his ideas on ethics, politics, and metaphysics that have shaped the world for centuries.",
		Image:       "aristotle.png",
		CurrentlyOpened: true,
	},
}

func GetAll() []Exhibition {
	return list
}

func Add(exb Exhibition) {
	list = append(list, exb)
}

We can test the data layer by add two api endpoints

  • GET: /api/exhibitions
  • POST: /api/exhibitions/new

 

API Layer

// @filename: api/get.go

package api

import (
	"encoding/json"
	"net/http"
	"strconv"

	"project/museum/data"
)

func Get(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    // /api/exhibitions?id=1
    id := r.URL.Query()["id"]
    if id != nil {
        finalId, err := strconv.Atoi(id[0]) // parseInt
        if err == nil && finalId < len(data.GetAll()) {
            // Send one item back to Client using json encoder
            json.NewEncoder(w).Encode(data.GetAll()[finalId])
        } else {
            http.Error(w, "Invalid Exhibition", http.StatusBadRequest)
        }
    } else {
        // Send all item to client
        json.NewEncoder(w).Encode(data.GetAll())
    }
}
// @filename: api/post.go

package api

import (
	"encoding/json"
	"net/http"

	"project/museum/data"
)

func Post(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodPost {
		var item data.Exhibition
        // Read data from client
		err := json.NewDecoder(r.Body).Decode(&item)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		data.Add(item)
		w.WriteHeader(http.StatusCreated)
		w.Write(([]byte("OK")))
	} else {
		http.Error(w, "Unsupported Method", http.StatusMethodNotAllowed)
	}
}

 

Now we can link those two api in our server

// @filename: main.go
package main

import (
	"fmt"
	"net/http"
    
    "project/museum/api"
	"project/museum/data"
)

func handleHello (res http.ResponseWriter, req *http.Request) {
    // Covert to []bytpe type
	res.Write([]byte("Hello from a Go program"))
}

func main {
    server := http.NewServeMux()
    server.HandleFunc("/hello", handleHello)
    // Get and Post
    server.handleFunc("/api/exhibitions", api.Get)
    server.handleFunc("/api/exhibitions", api.Post)
    
    // Serve public files
    fs := http.FileServer(http.Dir("./public"))
    server.Handle("/", fs)
    
    err := http.ListenAndServe(":3333", server)
    if err != nil {
        fmt.Println("Server cannot start")
    }
}

Rerun the server, then you can use POSTMAN to check apis.

 

Template

Now we want to display the data in our client by using template, so that we can do server side rendering which is more performance compare to Client side data fetching + rendering

// @filename: templates/index.tmpl

<!DOCTYPE html>
<html lang="en">
  <head>
    ...
  </head>
  <body>
    <main>
      {{ range .}}
      <article
        class="{{- if .CurrentlyOpened -}} opened {{- else -}} closed {{- end -}}"
      >
        <h2>{{ .Title }}</h2>
        <p>
          {{ .Description }}
        </p>
        <img src="gallery/{{ .Image }}" fetchpriority="high" decoding="sync" />
      </article>
      {{ end }}
    </main>
  </body>
</html>

So .means the whole data, because we will return an array of object, therefore we use rangeto foreach object, so the .represent each object

And you can see, it support logic condition {{ if cond }} A {{ else }} B {{ end }}

If you want to remove all the whie space, you can use -, then it becomes {{- if .CurrentlyOpened -}} opened {{- else -}} closed {{- end -}}

 

Let's serve the template

// @filename: main.go

package main

import (
	"fmt"
	"net/http"
	"text/template"

	"project/museum/api"
	"project/museum/data"
)

func handleHello (res http.ResponseWriter, req *http.Request) {
	res.Write([]byte("Hello from a Go program"))
}

func handleTemplate(res http.ResponseWriter, req *http.Request) {
	html, err := template.ParseFiles("templates/index.tmpl")
	if err != nil {
		res.WriteHeader(http.StatusInternalServerError)
		res.Write([]byte("Internal Server Error"))
	
		return
	}
	// Send data to template
	html.Execute(res, data.GetAll())
}

func main() {
	// Create a route handler
	server := http.NewServeMux()
	server.HandleFunc("/hello", handleHello)
    // Get and Post
	server.HandleFunc("/api/exhibitions", api.Get)
	server.HandleFunc("/api/exhibitions/new", api.Post)
    // template
    server.HandleFunc("/templates", handleTemplate)
	// Server public files
	fs := http.FileServer(http.Dir("./public"))
	server.Handle("/", fs)

	err := http.ListenAndServe(":3333", server)
	if err != nil {
		fmt.Println("Server cannot start")
	}
}

DONE. If you change template and css, js you don't need to restart the Go server

标签:http,err,simple,server,api,func,Go,data
From: https://www.cnblogs.com/Answer1215/p/18012506

相关文章

  • python django4.1 pycharm,报错,Conflicting 'xxx' models in application 'xxx': <
    遇到了一个报错,不知道咋么解决,pythondjango3pycharm,报错。不晓得怎么解决;Conflicting'xxx'modelsinapplication'xxx':<class'xxx'>and<class'xxx'>.这个是 报错误 信息,如下:RuntimeError:Conflicting'faculty'modelsin......
  • Install Anaconda On the Linux Server
    DownloadtheAnacondaPackageFirstly,weneedtogettheanaconda3packageandthereissomemirrorswebsiteprovidingthefasterspeedofdownloading.There,wechosenthetsinghuamirrorandtheversionof2023.09withx86architecture.wgethttps://mi......
  • Asp-Net-Core学习笔记:4.Blazor-Server入门
    本来今天开始是有其他的安排了,也没办法抽出那么多时间来学NetCore,不过我想做事情有始有终吧,除了gRPC还没跑起来之外,Blazor这部分也了解了一点,官网地址:https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor目前来说还不是很完善,真正的离线单页应用还处于预览版阶段。Blazo......
  • golang容器部署时区报错
    问题:consttimezone="Asia/Shanghai"funcTimeFormat(datetime.Time,patternstring)string{location,err:=time.LoadLocation(timezone)date.In(location)returndate.Format(pattern)} 1.在本地开发使用了时区是没有问题的,但是部署到服务器上面......
  • 分布式事务(七):Seata-Server的搭建
    1、Seata-Server下载官方文档地址:https://seata.io/zh-cn/docs/ops/deploy-guide-beginner.html。下载地址:https://github.com/seata/seata/releases,这里下载的是1.5.1版本,seata-server-1.5.1.tar.gz。 解压文件目录如下 2、注册中心配置Seata支持的注......
  • [ABC327G] Many Good Tuple Problems 题解
    Description对于一对长度均为\(M\)且元素值在\(\left[1,N\right]\)之间的序列\((S,T)\),定义其为好的当且仅当:存在一个长度为\(N\)的\(01\)序列\(X\),使得其满足如下条件:对于任意\(i\in\left[1,M\right]\),有\(X_{S_i}\neqX_{T_i}\)。给定\(N,M\),求在......
  • golang之枚举类型iota
    枚举类型是一种常用的数据类型,用于表示一组有限的、预定义的、具名的常量值。在枚举类型中,每个常量都是一个枚举值,它们之间的值相等且唯一。枚举类型通常用于表示一组相关的常量,比如星期、月份、性别等等。在其他语言里(比如Java和C),都内置了枚举类型,而在Go语言里是没有内置......
  • go简单部署到ubuntu
    一、概述做了一个简单的服务用来下载文件,这里主要使用来下载apk,然后生成一个二维码给用户下载apk使用。 二、步骤1.在ubuntu上安装go环境并配置环境变量(网上一大堆)2.在Windows交叉打包一个可以运行在ubuntu上的可执行文件。打包命令file_download_service:可......
  • Go语言精进之路读书笔记第19条——理解Go语言表达式的求值顺序
    第19条了解Go语言控制语句惯用法及使用注意事项19.1使用if控制语句时应遵循"快乐路径"原则当出现错误时,快速返回;成功逻辑不要嵌入if-else语句中;"快乐路径"当执行逻辑中代码布局上始终靠左,这样读者可以一眼看到该函数当正常逻辑流程;"快乐路径"的返回值一般在函数最后一行。......
  • Go语言精进之路读书笔记第17条——理解Go语言表达式的求值顺序
    Go语言表达式支持在同一行声明和初始化多个变量支持在同一行对多个变量进行赋值(不同类型也可以)vara,b,c=5,"hello",3.45a,b,c:=5,"hello",3.45a,b,c=5,"hello",3.45RobPike练习题(规则见17.3赋值语句的求值)n0,n1=n0+n1,n0或者n0,n1=op(......