eia-api-go/pkg/eia/eia.go
2024-12-05 12:59:02 -05:00

132 lines
3.6 KiB
Go

package eia
import (
"context"
"errors"
"fmt"
"net/url"
"slices"
"strings"
"time"
"github.com/deepmap/oapi-codegen/pkg/securityprovider"
"github.com/rs/zerolog"
eiaapi "gitea.libretechconsulting.com/50W/eia-api-go/api"
)
const (
defaultBaseURL = "https://api.eia.gov"
defaultPingTimeout = 10 * time.Second
defaultLogLevel = zerolog.DebugLevel
)
// Simple wrapper around generated EIA API client
// that embeds a client with a bearer auth interceptor
// and optional logging middleware
//
// Performs a basic availability check against the API
// when creating a new client, and exposes a Ping() method
// for health / readiness probes
type Client struct {
ctx context.Context
apiKey string
healthCheckTimeout time.Duration
*eiaapi.Client
*eiaapi.ClientWithResponses
}
type ClientOpts struct {
Context context.Context // Base context for requests
APIKey string // API Key [EIA Opendata API v2](https://www.eia.gov/opendata/index.php)
Logger *zerolog.Logger // Optional logger, if set is injected into logging middleware
LogLevel *zerolog.Level // Optional log level, default is zerolog.DebugLevel
BaseURL *url.URL // Optional, default is https://api.eia.gov
HealthCheckTimeout *time.Duration // Timeout for Ping() function, default is 10s
}
type Facet struct {
Name string
Data interface{}
}
func NewFacets(facets ...*Facet) *eiaapi.Facets {
newFacets := make(map[string]interface{}, len(facets))
for _, f := range facets {
for i := 0; ; i++ {
if _, set := newFacets[fmt.Sprintf("facets[%s][%d]", f.Name, i)]; set {
continue
}
newFacets[fmt.Sprintf("facets[%s][%d]", f.Name, i)] = f.Data
break
}
}
return &newFacets
}
func NewClient(opts *ClientOpts) (*Client, error) {
baseURL := defaultBaseURL
if opts.BaseURL != nil {
if !strings.HasPrefix(opts.BaseURL.Scheme, "http") {
return nil, errors.New("invalid scheme, only http or https supported")
}
baseURL = opts.BaseURL.String()
if _, err := url.Parse(baseURL); err != nil {
return nil, err
}
}
hcTimeout := defaultPingTimeout
if opts.HealthCheckTimeout != nil && *opts.HealthCheckTimeout > time.Duration(0) {
hcTimeout = *opts.HealthCheckTimeout
}
middlewares := make([]eiaapi.ClientOption, 0, 2)
// Injects Authorization: Bearer <APIKey> header into
// outbound API calls
// basicAuth, err := securityprovider.NewSecurityProviderBearerToken(opts.APIKey)
// if err != nil {
// return nil, err
// }
// middlewares = append(middlewares, eiaapi.WithRequestEditorFn(basicAuth.Intercept))
// Injects API key as query parameter: ?api_key=<apiKey>
paramAuth, err := securityprovider.NewSecurityProviderApiKey("query", "api_key", opts.APIKey)
if err != nil {
return nil, err
}
middlewares = append(middlewares, eiaapi.WithRequestEditorFn(paramAuth.Intercept))
// Logging middleware, if logger is given
if opts.Logger != nil {
logLevel := defaultLogLevel
if opts.LogLevel != nil {
logLevel = *opts.LogLevel
}
middlewares = append(middlewares,
eiaapi.WithRequestEditorFn(newLoggingMiddleware(opts.Logger, logLevel)))
}
client, err := eiaapi.NewClient(baseURL, slices.Clip(middlewares)...)
if err != nil {
return nil, err
}
clientWithResponses, err := eiaapi.NewClientWithResponses(baseURL, slices.Clip(middlewares)...)
if err != nil {
return nil, err
}
return &Client{
apiKey: opts.APIKey,
ctx: opts.Context,
healthCheckTimeout: hcTimeout,
Client: client,
ClientWithResponses: clientWithResponses,
}, nil
}