mirror of
https://github.com/Crocmagnon/lyon-transports.git
synced 2024-12-03 11:16:00 +01:00
add velov
This commit is contained in:
parent
463513e78b
commit
a29feca6ff
4 changed files with 120 additions and 1 deletions
21
main.go
21
main.go
|
@ -28,6 +28,10 @@ type stopOutput struct {
|
|||
Body Passages
|
||||
}
|
||||
|
||||
type velovOutput struct {
|
||||
Body Station
|
||||
}
|
||||
|
||||
func addRoutes(api huma.API, glConfig GrandLyonConfig, now func() time.Time) {
|
||||
huma.Register(api, huma.Operation{
|
||||
OperationID: "healthcheck",
|
||||
|
@ -42,7 +46,7 @@ func addRoutes(api huma.API, glConfig GrandLyonConfig, now func() time.Time) {
|
|||
})
|
||||
|
||||
huma.Get(api, "/tcl/stop/{stopID}", func(ctx context.Context, input *struct {
|
||||
StopID int `path:"stopID" doc:"Stop id to monitor. Can be obtained using https://data.grandlyon.com/jeux-de-donnees/points-arret-reseau-transports-commun-lyonnais/donnees"`
|
||||
StopID int `path:"stopID" doc:"Stop id to monitor. Can be obtained using https://data.grandlyon.com/portail/fr/jeux-de-donnees/points-arret-reseau-transports-commun-lyonnais/donnees"`
|
||||
}) (*stopOutput, error) {
|
||||
passages, err := getPassages(ctx, glConfig, now, input.StopID)
|
||||
if errors.Is(err, errNoPassageFound) {
|
||||
|
@ -55,6 +59,21 @@ func addRoutes(api huma.API, glConfig GrandLyonConfig, now func() time.Time) {
|
|||
|
||||
return &stopOutput{Body: *passages}, nil
|
||||
})
|
||||
|
||||
huma.Get(api, "/velov/station/{stationID}", func(ctx context.Context, input *struct {
|
||||
StationID int `path:"stationID" doc:"Station id to monitor. Can be obtained using https://data.grandlyon.com/portail/fr/jeux-de-donnees/stations-velo-v-metropole-lyon/donnees"`
|
||||
}) (*velovOutput, error) {
|
||||
station, err := getStation(ctx, glConfig.Client, input.StationID)
|
||||
if errors.Is(err, errStationNotFound) {
|
||||
return nil, huma.NewError(http.StatusNotFound, "station not found")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &velovOutput{Body: *station}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
42
main_test.go
42
main_test.go
|
@ -86,3 +86,45 @@ func TestGetStop(t *testing.T) {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetVelovStation(t *testing.T) {
|
||||
_, api := humatest.New(t)
|
||||
|
||||
transport := httpmock.NewMockTransport()
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
config := GrandLyonConfig{
|
||||
Client: client,
|
||||
}
|
||||
|
||||
transport.RegisterResponder(http.MethodGet,
|
||||
"https://data.grandlyon.com/fr/datapusher/ws/rdata/jcd_jcdecaux.jcdvelov/all.json?maxfeatures=-1&start=1",
|
||||
httpmock.NewBytesResponder(http.StatusOK, httpmock.File("./testdata/station_info.json").Bytes()))
|
||||
//transport.RegisterResponder(http.MethodGet,
|
||||
// "https://download.data.grandlyon.com/files/rdata/jcd_jcdecaux.jcdvelov/station_status.json",
|
||||
// httpmock.NewBytesResponder(http.StatusOK, httpmock.File("./testdata/station_status.json").Bytes()))
|
||||
|
||||
addRoutes(api, config, time.Now)
|
||||
|
||||
t.Run("station not found", func(t *testing.T) {
|
||||
resp := api.Get("/velov/station/0")
|
||||
assert.Equal(t, resp.Code, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("station exists", func(t *testing.T) {
|
||||
resp := api.Get("/velov/station/10039")
|
||||
assert.Equal(t, resp.Code, http.StatusOK)
|
||||
|
||||
var station Station
|
||||
err := json.Unmarshal(resp.Body.Bytes(), &station)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.DeepEqual(t, station, Station{
|
||||
Name: "10039 - BOUVIER",
|
||||
BikesAvailable: 9,
|
||||
DocksAvailable: 7,
|
||||
AvailabilityCode: 1,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
1
testdata/station_info.json
vendored
Normal file
1
testdata/station_info.json
vendored
Normal file
File diff suppressed because one or more lines are too long
57
velov.go
Normal file
57
velov.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/carlmjohnson/requests"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Station struct {
|
||||
Name string `json:"name"`
|
||||
BikesAvailable int `json:"bikes_available"`
|
||||
DocksAvailable int `json:"docks_available"`
|
||||
AvailabilityCode int `json:"availability_code"`
|
||||
}
|
||||
|
||||
type stationInfo struct {
|
||||
Values []struct {
|
||||
AvailabilityCode int `json:"availabilitycode"`
|
||||
AvailableBikeStands int `json:"available_bike_stands"`
|
||||
AvailableBikes int `json:"available_bikes"`
|
||||
Name string `json:"name"`
|
||||
Number int `json:"number"`
|
||||
} `json:"values"`
|
||||
}
|
||||
|
||||
var errStationNotFound = errors.New("station not found")
|
||||
|
||||
func getStation(ctx context.Context, client *http.Client, stationID int) (*Station, error) {
|
||||
var info stationInfo
|
||||
err := requests.URL("https://data.grandlyon.com/fr/datapusher/ws/rdata/jcd_jcdecaux.jcdvelov/all.json?maxfeatures=-1&start=1").
|
||||
Client(client).
|
||||
ToJSON(&info).
|
||||
Fetch(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying station info: %w", err)
|
||||
}
|
||||
|
||||
station := Station{}
|
||||
|
||||
for _, sInfo := range info.Values {
|
||||
if sInfo.Number == stationID {
|
||||
station.Name = sInfo.Name
|
||||
station.BikesAvailable = sInfo.AvailableBikes
|
||||
station.DocksAvailable = sInfo.AvailableBikeStands
|
||||
station.AvailabilityCode = sInfo.AvailabilityCode
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if station.Name == "" {
|
||||
return nil, errStationNotFound
|
||||
}
|
||||
|
||||
return &station, nil
|
||||
}
|
Loading…
Reference in a new issue