DocsGo

Backend Integration - Go

Go's standard net/http package handles the proxy with minimal overhead. The only external dependency is gorilla/websocket for the tracking relay.

1

Initialize module

go mod init yourapp
go get github.com/gorilla/websocket

Set PICKPOINT_KEY in your shell environment or in a .env file loaded at startup.

2

Helper functions and setup

// main.go
package main

import (
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
)

const pickpointBase = "https://api.pickpoint.io/v2"

var pickpointKey = os.Getenv("PICKPOINT_KEY")

// proxy forwards a GET request to PickPoint, copying query params.
func proxy(w http.ResponseWriter, r *http.Request, path string) {
	target, _ := url.Parse(pickpointBase + path)
	target.RawQuery = r.URL.RawQuery

	req, _ := http.NewRequestWithContext(r.Context(), "GET", target.String(), nil)
	req.Header.Set("X-Api-Key", pickpointKey)

	resp, err := http.DefaultClient.Do(req)
	if err != nil { http.Error(w, err.Error(), 502); return }
	defer resp.Body.Close()

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}

// proxyPost forwards a POST request with the request body to PickPoint.
func proxyPost(w http.ResponseWriter, r *http.Request, path string) {
	req, _ := http.NewRequestWithContext(r.Context(), "POST", pickpointBase+path, r.Body)
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("X-Api-Key", pickpointKey)

	resp, err := http.DefaultClient.Do(req)
	if err != nil { http.Error(w, err.Error(), 502); return }
	defer resp.Body.Close()

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}
3

Routes: geocoding, routing, devices

func main() {
	mux := http.NewServeMux()

	// ── Geocoding ──────────────────────────────────────────────────────────
	mux.HandleFunc("GET /geo/forward", func(w http.ResponseWriter, r *http.Request) {
		proxy(w, r, "/geocode/forward")
	})
	mux.HandleFunc("GET /geo/reverse", func(w http.ResponseWriter, r *http.Request) {
		proxy(w, r, "/geocode/reverse")
	})
	mux.HandleFunc("GET /geo/search", func(w http.ResponseWriter, r *http.Request) {
		proxy(w, r, "/address/search")
	})

	// ── Routing ────────────────────────────────────────────────────────────
	mux.HandleFunc("POST /route", func(w http.ResponseWriter, r *http.Request) {
		proxyPost(w, r, "/route")
	})
	mux.HandleFunc("POST /route/optimized", func(w http.ResponseWriter, r *http.Request) {
		proxyPost(w, r, "/route/optimized")
	})

	// ── Device Tracking - REST ─────────────────────────────────────────────
	mux.HandleFunc("GET /devices", func(w http.ResponseWriter, r *http.Request) {
		proxy(w, r, "/devices")
	})
	mux.HandleFunc("GET /devices/{uid}/tracks", func(w http.ResponseWriter, r *http.Request) {
		uid := r.PathValue("uid")
		proxy(w, r, "/devices/"+uid+"/tracks")
	})

	// ── WebSocket relay ────────────────────────────────────────────────────
	mux.HandleFunc("GET /tracking-relay", trackingRelay)

	log.Println("Listening on :3000")
	log.Fatal(http.ListenAndServe(":3000", mux))
}
4

WebSocket subscriber relay

// ── WebSocket subscriber relay ─────────────────────────────────────────────
import (
	"github.com/gorilla/websocket"
	// add to imports above
)

var upgrader = websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}

func trackingRelay(w http.ResponseWriter, r *http.Request) {
	deviceUID := r.URL.Query().Get("deviceUid")
	if deviceUID == "" { http.Error(w, "deviceUid required", 400); return }

	// Upgrade client connection
	clientConn, err := upgrader.Upgrade(w, r, nil)
	if err != nil { return }
	defer clientConn.Close()

	// Connect to PickPoint as a subscriber
	ppURL := "wss://ws.pickpoint.io/v2/tracking/?x-api-key=" + pickpointKey
	ppConn, _, err := websocket.DefaultDialer.DialContext(r.Context(), ppURL, nil)
	if err != nil { return }
	defer ppConn.Close()

	// Subscribe
	ppConn.WriteJSON(map[string]any{"event": "device:subscribe", "data": map[string]string{"deviceUid": deviceUID}})

	// Forward PickPoint messages to client
	for {
		_, msg, err := ppConn.ReadMessage()
		if err != nil { break }
		if err := clientConn.WriteMessage(websocket.TextMessage, msg); err != nil { break }
	}
}

← OverviewJava →