Skip to content

Instantly share code, notes, and snippets.

@scascketta
Last active June 9, 2019 05:58
Show Gist options
  • Save scascketta/cd3ded829de4a67b5a66 to your computer and use it in GitHub Desktop.
Save scascketta/cd3ded829de4a67b5a66 to your computer and use it in GitHub Desktop.
A Golang server to proxy XML requests, parse them to JSON, and add CORS headers.
application: scenic-cedar-88515
version: 1
runtime: go
api_version: go1
handlers:
- url: /.*
script: _go_app
package instaql
import (
"appengine"
"appengine/urlfetch"
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
)
func init() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
http.HandleFunc("/", CorsMiddleware(proxy))
}
func proxy(w http.ResponseWriter, r *http.Request) {
vals := r.URL.Query()
url := vals.Get("url")
if url == "" {
w.Write([]byte("No url provided"))
return
}
log.Println(url)
c := appengine.NewContext(r)
client := urlfetch.Client(c)
res, err := client.Get(url)
if err != nil {
http.Error(w, fmt.Sprintf("Error making request to %s: %s", url, err.Error()), http.StatusInternalServerError)
return
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
http.Error(w, "Error reading body from requested URL", http.StatusInternalServerError)
return
}
json, err := NextbusToJSON(body)
if err != nil {
http.Error(w, fmt.Sprintf("Error marshaling XML to JSON: %s", err.Error()), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(json)
return
}
func CorsMiddleware(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Methods", "GET, POST")
w.Header().Set("Access-Control-Max-Age", strconv.Itoa(60*60*6))
w.Header().Set("Access-Control-Allow-Headers", "CONTENT-TYPE, ACCEPT")
return
}
w.Header().Set("Access-Control-Allow-Origin", "*")
fn(w, r)
}
}
package instaql
import (
"encoding/json"
"encoding/xml"
"log"
)
type RunsData struct {
Runs []Run `xml:"Body>Nextbus2Response>Runs>Run" json:"runs"`
}
type Run struct {
Route string `json:"route"`
Sign string `json:"sign"`
Direction string `json:"direction"`
TripTime string `xml:"Triptime" json:"trip_time"`
TripID string `xml:"Tripid" json:"trip_id"`
Adherence string `json:"adherence"`
RealtimeValid string `xml:"Realtime>Valid" json:"valid"`
EstimatedTime string `xml:"Realtime>Estimatedtime" json:"estimated_time"`
PollTime string `xml:"Realtime>Polltime" json:"poll_time"`
VehicleID string `xml:"Realtime>Vehicleid" json:"vehicle_id"`
VehicleLon string `xml:"Realtime>Long" json:"vehicle_lon"`
VehicleLat string `xml:"Realtime>Lat" json:"vehicle_lat"`
Block string `json:"block"`
StopID string `xml:"Stopid" json:"stop_id"`
}
func NextbusToJSON(data []byte) ([]byte, error) {
xmlData := new(RunsData)
err := xml.Unmarshal(data, xmlData)
if err != nil {
log.Println(err)
return nil, err
}
res, err := json.Marshal(xmlData)
return res, err
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment