SoFunction
Updated on 2025-03-01

Sample code of simple API gateway implemented based on Go language

The browser requests the target address, and then gets the result and sends it to the browser. For Go, implementing forwarding only requires a simple line of code to implement it, as shown below:

(address)

Based on this function, simple packaging is carried out to obtain the routing information that needs to be forwarded from the remote admin management center or can be obtained from the local configuration file to achieve dynamic forwarding. The following functions can be implemented according to the business situation in the future:
Develop interfaces to dynamically add proxy rules and forward them

  • Illegal filtering interfaces
  • Interface current limit
  • Unified logging

The code is as follows:

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"/gin-gonic/gin"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strings"
)

type Respond struct {
	Success bool
	Status  string
	Data    []Proxy
}

type Proxy struct {
	Remark        string //describe	Prefix        string //Forwarding prefix judgment	Upstream      string //Backend nginx address or IP address	RewritePrefix string //Rewrite}

var (
	InfoLog  *
	ErrorLog *
	proxyMap = make(map[string]Proxy)
)

var adminUrl = ("adminUrl", "", "adminAddress")
var profile = ("profile", "", "environment")
var proxyFile = ("proxyFile", "", "测试environment的数据")

//Log initializationfunc initLog() {
	errFile, err := ("", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	infoFile, err := ("", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		("Login file failed:", err)
	}
	InfoLog = ((, infoFile), "Info:", ||)
	ErrorLog = ((, errFile), "Error:", ||)
}

func main() {
	router := () //Create a router	()
	initLog()
	if *profile != "" {
		("Loading remote data: %s", *adminUrl)
		initProxyList()
	} else {
		("Load local configuration data: %s", *proxyFile)
		loadProxyListFromFile()
	}
	("/*action", Forward) //All requests will be forwarded by the Forward function
	(":8000")
}

func initProxyList() {
	resp, _ := (*adminUrl)
	if resp != nil &&  == 200 {
		bytes, err := ()
		defer ()
		if err != nil {
			(" err=", err)
			return
		}
		var respond Respond
		err = (bytes, &respond)
		if err != nil {
			(" err=", err)
			return
		}
		proxyList := 
		for _, proxy := range proxyList {
			//Add backslash to prevent /proxy/test /proxy/test1 from being forwarded correctly when dynamically matched			proxyMap[+"/"] = proxy
		}
	}
}

func Forward(c *) {
	HostReverseProxy(, )
}

func HostReverseProxy(w , r *) {
	if  == "/" {
		(w, "Request path Error")
		return
	}
	//Get forwarded url from memory	var upstream = ""
	if value, ok := proxyMap[]; ok {
		//If the forwarding address starts with /, it needs to be removed		if (, "/") {
			upstream += (, "/")
		} else {
			upstream += 
		}
		//If the first position is not the beginning, you need to add it		if !(, "/") {
			upstream += "/" + 
		} else {
			upstream += 
		}
		//Remove the beginning		 = (, , "")
	}

	// parse the url
	remote, err := (upstream)
	("RequestURI %s upstream %s remote %s", , upstream, remote)
	if err != nil {
		panic(err)
	}

	 = 
	 = 
	("X-Forwarded-Host", ("Host"))
	 = 

	(remote).ServeHTTP(w, r)
}

func loadProxyListFromFile() {
	file, err := (*proxyFile)
	if err != nil {
		("err:", err)
	}
	var respond Respond
	// Create a json decoder	decoder := (file)
	err = (&respond)
	if err != nil {
		("LoadProxyListFromFile failed", ())
	}
	proxyList := 
	for _, proxy := range proxyList {
		proxyMap[+"/"] = proxy
	}
}

The format of proxy_data.json is as follows:

{
  "success":true,
  "status": "ok",
  "data": [
    {
      "remark": "Test Environment",
      "prefix": "/division",
      "upstream": "/",
      "rewritePrefix": "/api/division"
    },
    {
      "remark": "Test Environment 1",
      "prefix": "/division1",
      "upstream": "/",
      "rewritePrefix": ""
    },
    {
      "remark": "Test Environment 2",
      "prefix": "/division3",
      "upstream": "/",
      "rewritePrefix": "/api/division"
    }
  ]
}

Start the script

## Load local configuration file datago run proxy_agent.go -proxyFile ./proxy_data.json
## Start to get data from the configuration centergo run proxy_agent.go -profile prod -adminUrl http://localhost:3000/proxy/findAll

This is the article about the sample code of the simple API gateway implemented based on Go language. For more related Go API gateway content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!