1package main23// This file contains the routines and information necessary to talk to the MBTA API45import (6 "encoding/json"7 "fmt"8 "io/ioutil"9 "log"10 "net/http"11 "strconv"12 "strings"13)1415type apiResponse struct {16 Data []struct {17 Attributes struct {18 DirectionID int `json:"direction_id"`19 Label string `json:"label"`20 } `json:"attributes"`21 Relationships struct {22 Route struct {23 Data struct {24 ID string `json:"id"`25 } `json:"data"`26 } `json:"route"`27 Stop struct {28 Data struct {29 ID string `json:"id"`30 } `json:"data"`31 } `json:"stop"`32 Trip struct {33 Data struct {34 ID string `json:"id"`35 } `json:"data"`36 } `json:"trip"`37 } `json:"relationships"`38 } `json:"data"`39 Included []struct {40 Attributes struct {41 Name string `json:"name"`42 } `json:"attributes"`43 ID string `json:"id"`44 } `json:"included"`45}4647// Calls into the MBTA API to retrieve a list of all trains. and returns a list48// of all of them, or an error if there was one.49//50// No filtering is performed. That is the job of the caller.51func GetTrains() ([]Train, error) {52 resp, err := http.Get(apiEndpoint)53 if err != nil {54 return nil, fmt.Errorf("unable to query MBTA API: %v", err)55 }56 defer resp.Body.Close()5758 if resp.StatusCode != http.StatusOK {59 errorStr := fmt.Sprintf("Received non-200 result from API: %v", resp.StatusCode)60 log.Println(errorStr)61 return nil, fmt.Errorf(errorStr)62 }6364 body, err := ioutil.ReadAll(resp.Body)65 if err != nil {66 return nil, fmt.Errorf("unable to read API response: %v", err)67 }6869 var decoded apiResponse70 if err := json.Unmarshal(body, &decoded); err != nil {71 return nil, fmt.Errorf("unable to unmarshal JSON response: %v", err)72 }7374 stopNames := make(map[string]string)75 for _, stop := range decoded.Included {76 stopNames[stop.ID] = stop.Attributes.Name77 }7879 trains := make([]Train, 0)80 for _, train := range decoded.Data {81 labelStrs := strings.Split(train.Attributes.Label, "-")82 labels := make([]int, 0)83 for _, label := range labelStrs {84 v, err := strconv.Atoi(label)85 if err != nil {86 // It seems like sometimes we end up with empty87 // cars. There's probably a trailing dash.88 if label == "" {89 log.Println("Found strange cars list: ", train.Attributes.Label)90 continue91 }92 panic(err)93 }94 labels = append(labels, v)95 }9697 line := StringToLine(train.Relationships.Route.Data.ID)9899 if line == LineUnknown {100 panic("unknown line: " + train.Relationships.Route.Data.ID)101 }102103 trains = append(trains, Train{104 Line: line,105 Cars: labels,106 Stop: stopNames[train.Relationships.Stop.Data.ID],107 Direction: IntToDirection(train.Attributes.DirectionID, line),108 Trip: train.Relationships.Trip.Data.ID,109 })110 }111112 return trains, nil113}