Go implementation of client, server and validator for GBFS (General Bikeshare Feed Specification).
import "github.com/petoc/gbfs"
c, err := gbfs.NewClient(gbfs.ClientOptions{
AutoDiscoveryURL: "http://127.0.0.1:8080/v3/system_id/gbfs.json",
DefaultLanguage: "en",
})
if err != nil {
log.Fatal(err)
}
f := &gbfs.FeedSystemInformation{}
err := c.Get(f)
if err != nil {
log.Println(err)
}
if f.Data != nil {
log.Printf("feed=%s system_id=%s", f.Name(), *f.Data.SystemID)
}
Client provides built-in function to handle feed updates.
err := c.Subscribe(gbfs.ClientSubscribeOptions{
// Languages: []string{"en"},
// FeedNames: []string{gbfs.FeedNameStationInformation, gbfs.FeedNameFreeBikeStatus},
Handler: func(c *gbfs.Client, f gbfs.Feed, err error) {
if err != nil {
log.Println(err)
return
}
j, _ := json.Marshal(f)
log.Printf("feed=%s data=%s", f.Name(), j)
},
})
if err != nil {
log.Println(err)
}
Subscription options Languages
and FeedNames
restrict subscription only to selected languages and feeds.
import "github.com/petoc/gbfs"
s, err := gbfs.NewServer(gbfs.ServerOptions{
SystemID: "system_id",
RootDir: "public",
BaseURL: "http://127.0.0.1:8080",
BasePath: "v3/system_id",
Version: gbfs.V30,
DefaultTTL: 60,
FeedHandlers: []*gbfs.FeedHandler{
// see example for how to add feed handlers
},
UpdateHandler: func(s *gbfs.Server, feed gbfs.Feed, path string, err error) {
if err != nil {
log.Println(err)
return
}
log.Printf("system=%s ttl=%d version=%s updated=%s", s.Options.SystemID, feed.GetTTL(), feed.GetVersion(), path)
},
})
if err != nil {
log.Fatal(err)
}
log.Fatal(s.Start())
Main autodiscovery feed gbfs.json
will be constructed from all available feeds in FeedHandlers
. After that, all FeedHandlers
will be regularly executed after configured TTL
. If TTL
is not set for individual feeds, it will be inherited from FeedHandler
. If TTL
is not set even for FeedHandler, DefaultTTL
from ServerOptions
will be used for feed.
Feeds can be served as static files with standard webservers (Nginx, Apache, ...) or with simple built-in static file server.
fs, err := gbfs.NewFileServer("127.0.0.1:8080", "public")
if err != nil {
log.Fatal(err)
}
log.Fatal(fs.ListenAndServe())
Validator validates feeds for common issues, such as missing required fields, invalid values, mutually exclusive fields, and so on. Validation result contains parsed feed in Feed
struct and slices of Infos
, Warnings
and Errors
. Important validation issues will be in Errors
. Warnings
usually comply with specification, but should be considered in order to be consistent with most of providers. Infos
contains just notes, such as usage of field officialy available from newer versions of specification.
Not all invalid type issues will be reported, only common ones like coordinates or prices as strings, instead of float. Other uncommon type issues will prevent feed from being parsed. In such cases, some reasonable error should be returned from client.
import "github.com/petoc/gbfs/validator"
f := &gbfs.FeedSystemInformation{}
err := c.Get(f)
if err != nil {
log.Fatal(err)
}
v := validator.New()
r := v.Validate(f, gbfs.V10)
log.Printf("infos=%v", r.Infos)
log.Printf("warnings=%v", r.Warnings)
log.Printf("errors=%v", r.Errors)
Licensed under MIT license.