A Go (golang) client library for the Duffel Flights API originally implemented by the Airheart team.
This fork contains some significant improvements:
- Implemented backoff retry mechanism
- Added missing error codes and flight structures
- Added request options
- Added partial offer request functionality
We've designed this pkg to be familiar and ideomatic to any Go developer. Go get it the usual way:
NOTE: Requires at least Go 1.18 since we use generics on the internal API client
go get github.com/airheartdev/duffel
See the examples/* directory
The easiest way to get started, assuming you have a Duffel account set up and an API key ready, is to create an API instance and make your first request:
// Create a new client:
dfl := duffel.New(os.Getenv("DUFFEL_TOKEN"))
For available methods, see:
And familiarise yourself with the implementation notes:
All models that have fields for an amount and a currency implement a method to return a parsed currency.Amount{}
total:= order.TotalAmount() // currency.Amount
total.Currency // USD
total.Amount // 100.00
total.String() // 100.00 USD
All requests that return more than one record will return an iterator. An Iterator automatically paginates results and respects rate limits, reducing the complexity of the overall programming model.
dfl := duffel.New(os.Getenv("DUFFEL_TOKEN"))
iter := dfl.ListAirports(ctx, duffel.ListAirportsParams{
IATACountryCode: "AU",
})
for iter.Next() {
airport := iter.Current()
fmt.Printf("%s\n", airport.Name)
}
// If there was an error, the loop above will exit so that you can
// inspect the error here:
if iter.Err() != nil {
log.Fatalln(iter.Err())
}
We've added a convenience method to collect all items from the iterator into a single slice in one go:
airports, err := duffel.Collect(iter)
if err != nil {
// Handle error from iter.Err()
}
// airports is a []*duffel.Airport
Every response from Duffel includes a request ID that can be used to help debug issues with Duffel support. You should log the request ID for each operation in your app so that you can track down issues later on.
dfl := duffel.New(os.Getenv("DUFFEL_TOKEN"))
// Request IDs from Iterators:
iter := dfl.ListAirports(ctx, duffel.ListAirportsParams{
IATACountryCode: "AU",
})
for iter.Next() {
airport := iter.Current()
fmt.Printf("%s\n", airport.Name)
if lastRequestID, ok:= iter.LastRequestID(); ok {
fmt.Printf("Last request ID: %s\n", lastRequestID)
// Note: each iteration might be from the same page of data with the same request ID.
}
}
// Request IDs from other operations
data, err := client.CreateOfferRequest(context.Background(), duffel.OfferRequestInput{}
// ...
if lastRequestID, ok:= dfl.LastRequestID(); ok {
fmt.Printf("Last request ID: %s\n", lastRequestID)
}
Sometimes you need to make a retry request, retry algorithm depends on your purposes, currently, we support exponental backoff from the box but you can provide your own implementing dapi.RetryFunc
. You can specify retry attempts, wait time, and maximal wait time to retry the request. Also you have to provide a retry condition, the retry mechanism won't work without at least 1 condition.
client := dapi.New("duffel_test_123",
// Specify retry attempts, wait time and maximal wait time
dapi.WithRetry(3, time.Second, time.Second*3),
dapi.WithRetryCondition(func(resp *http.Response, err error) bool {
if e, ok := err.(*dapi.DuffelError); ok {
return e.Retryable // retry only if duffel error is retryable
}
return false
}),
)
Each API method returns an error or an iterator that returns errors at each iteration. If an error is returned from Duffel, it will be of type DuffelError
and expose more details on how to handle it.
// Example error inspection after making an API call:
offer, err := dfl.GetOffer(ctx, "off_123")
if err != nil {
// Simple error code check
if duffel.IsErrorCode(err, duffel.AirlineInternal) {
// Don't retry airline errors, contact support
}
// Access the DuffelError object to see more detail
if derr, ok:= err.(*duffel.DuffelError); ok {
// derr.Errors[0].Type etc
// derr.IsCode(duffel.BadRequest)
}else{
// Do something with regular Go error
}
}
IsErrorCode
is a concenience method to check if an error is a specific error code from Duffel.
This simplifies error handling branches without needing to type cast multiple times in your code.
IsErrorType
is a concenience method to check if an error is a specific error type from Duffel.
This simplifies error handling branches without needing to type cast multiple times in your code.
You can also check the derr.Retryable
field, which will be false if you need to contact Duffel support to resolve the issue, and should not be retried. Example, creating an order.
To maintain simplicity and ease of use, this client library is hand-coded (instead of using Postman to Go code generation) and contributions are greatly apprecicated.
- Types for all API models
- API Client
- Error handling
- Pagination (using iterators)
- Rate Limiting (automatically throttles requests to stay under limit)
- Offer Requests
- Partial Offer Requests
- Offers
- Orders
- Seat Maps
- Order Cancellations
- Order Change Requests
- Order Change Offers
- Order Changes
- Airports
- Airlines
- Equipment (Aircraft)
- Payments
- Places
This source code is licensed under the Apache 2.0 license found in the LICENSE file in the root directory of this source tree.