multimodal-routing/libs/transit/transitous/client.go

107 lines
2.6 KiB
Go

package transitous
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
"github.com/rs/zerolog/log"
)
// Client represents a Transitous API client
type Client struct {
baseURL string
httpClient *http.Client
}
// NewClient creates a new Transitous client
func NewClient(baseURL string) *Client {
return &Client{
baseURL: baseURL,
httpClient: &http.Client{
Timeout: 30 * time.Second,
},
}
}
// PlanParams represents the parameters for route planning
type PlanParams struct {
FromPlace string
ToPlace string
Time *time.Time
}
// PlanResponse represents the response from the Transitous API
type PlanResponse struct {
Itineraries []Itinerary `json:"itineraries"`
}
// PlanWithResponse plans a route and returns the response
func (c *Client) PlanWithResponse(ctx context.Context, params *PlanParams) (*TransitousResponse, error) {
// Build URL with query parameters
u, err := url.Parse(fmt.Sprintf("%s/api/v4/plan", c.baseURL))
if err != nil {
return nil, fmt.Errorf("failed to parse base URL: %w", err)
}
query := u.Query()
query.Set("fromPlace", params.FromPlace)
query.Set("toPlace", params.ToPlace)
if params.Time != nil {
// Use ISO 8601 format with timezone like in the example
query.Set("time", params.Time.Format(time.RFC3339))
}
// Additional parameters matching the example
query.Set("withFares", "true")
query.Set("fastestDirectFactor", "1.5")
query.Set("joinInterlinedLegs", "false")
query.Set("maxMatchingDistance", "250")
// query.Set("arriveBy", "true")
u.RawQuery = query.Encode()
// Create HTTP request
req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", "COOPGO-Platform/1.0")
log.Debug().
Str("url", u.String()).
Msg("Making Transitous API request")
// Execute request
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API request failed with status %d", resp.StatusCode)
}
// Parse response
var transitousResponse TransitousResponse
if err := json.NewDecoder(resp.Body).Decode(&transitousResponse); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
log.Debug().
Str("from", params.FromPlace).
Str("to", params.ToPlace).
Int("itineraries", len(transitousResponse.Itineraries)).
Msg("Transitous API response received")
return &transitousResponse, nil
}