Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
bd6d607
feat(client): allow custom baseurls without trailing slash (#69)
stainless-app[bot] Mar 8, 2025
249be00
feat: add SKIP_BREW env var to ./scripts/bootstrap (#71)
stainless-app[bot] Mar 11, 2025
8496c56
feat(client): accept RFC6838 JSON content types (#72)
stainless-app[bot] Mar 11, 2025
d2fd02d
refactor: tidy up dependencies (#73)
stainless-app[bot] Mar 11, 2025
703d7bc
feat(client): improve default client options support (#74)
stainless-app[bot] Mar 14, 2025
b943deb
chore(internal): remove extra empty newlines (#75)
stainless-app[bot] Mar 14, 2025
301ca94
chore(docs): improve security documentation (#76)
stainless-app[bot] Mar 25, 2025
a1409d6
chore: add request options to client tests (#77)
stainless-app[bot] Mar 26, 2025
a3975d5
fix(test): return early after test failure (#78)
stainless-app[bot] Mar 26, 2025
1b71db2
chore: fix typos (#79)
stainless-app[bot] Mar 27, 2025
5a6d7ab
codegen metadata
stainless-app[bot] Mar 27, 2025
70a742d
fix(client): return error on bad custom url instead of panic (#80)
stainless-app[bot] Apr 3, 2025
19d138e
feat(client): support custom http clients (#81)
stainless-app[bot] Apr 8, 2025
39a0bd5
chore(internal): expand CI branch coverage
stainless-app[bot] Apr 10, 2025
dd831b8
chore(internal): reduce CI branch coverage
stainless-app[bot] Apr 10, 2025
82d2142
docs: update documentation links to be more uniform
stainless-app[bot] Apr 15, 2025
1d1d81c
chore(docs): document pre-request options
stainless-app[bot] Apr 16, 2025
aa9e078
feat(client): add support for reading base URL from environment variable
stainless-app[bot] Apr 16, 2025
6c4e058
chore(ci): add timeout thresholds for CI jobs
stainless-app[bot] Apr 23, 2025
db7e619
chore(internal): codegen related update
stainless-app[bot] Apr 24, 2025
27ea834
chore(ci): only use depot for staging repos
stainless-app[bot] Apr 24, 2025
f117b7d
fix: handle empty bodies in WithJSONSet
stainless-app[bot] Apr 30, 2025
de2dbe6
release: 0.1.0-alpha.24
stainless-app[bot] Apr 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
- next
branches-ignore:
- 'generated'
- 'codegen/**'
- 'integrated/**'
- 'stl-preview-head/**'
- 'stl-preview-base/**'

jobs:
lint:
timeout-minutes: 10
name: lint
runs-on: ubuntu-latest

runs-on: ${{ github.repository == 'stainless-sdks/open-transit-go' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}

steps:
- uses: actions/checkout@v4
Expand All @@ -25,9 +25,9 @@ jobs:
- name: Run lints
run: ./scripts/lint
test:
timeout-minutes: 10
name: test
runs-on: ubuntu-latest

runs-on: ${{ github.repository == 'stainless-sdks/open-transit-go' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v4

Expand All @@ -41,4 +41,3 @@ jobs:

- name: Run tests
run: ./scripts/test

2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.1.0-alpha.23"
".": "0.1.0-alpha.24"
}
2 changes: 2 additions & 0 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
configured_endpoints: 29
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/open-transit%2Fopen-transit-6f08502508c8ad25235971add3124a1cde4f1c3ec705d5df455d750e0adcb90b.yml
openapi_spec_hash: 84d082f35446d29c7db3cfcd259e9859
config_hash: c7e112ec9853ad18fe92551ae0d97656
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,49 @@
# Changelog

## 0.1.0-alpha.24 (2025-04-30)

Full Changelog: [v0.1.0-alpha.23...v0.1.0-alpha.24](https://github.com/OneBusAway/go-sdk/compare/v0.1.0-alpha.23...v0.1.0-alpha.24)

### Features

* add SKIP_BREW env var to ./scripts/bootstrap ([#71](https://github.com/OneBusAway/go-sdk/issues/71)) ([249be00](https://github.com/OneBusAway/go-sdk/commit/249be00c6f37b9927493404b8d15f25cfce2a09c))
* **client:** accept RFC6838 JSON content types ([#72](https://github.com/OneBusAway/go-sdk/issues/72)) ([8496c56](https://github.com/OneBusAway/go-sdk/commit/8496c56f4eeef5023732a2df3c9520245273a693))
* **client:** add support for reading base URL from environment variable ([aa9e078](https://github.com/OneBusAway/go-sdk/commit/aa9e078338065441f57bbd9da3e0ab5c8ca31ee7))
* **client:** allow custom baseurls without trailing slash ([#69](https://github.com/OneBusAway/go-sdk/issues/69)) ([bd6d607](https://github.com/OneBusAway/go-sdk/commit/bd6d6078a909b7997f82794c70f3336dfc320802))
* **client:** improve default client options support ([#74](https://github.com/OneBusAway/go-sdk/issues/74)) ([703d7bc](https://github.com/OneBusAway/go-sdk/commit/703d7bce4e38e23971f26e64a99b335b2417785b))
* **client:** support custom http clients ([#81](https://github.com/OneBusAway/go-sdk/issues/81)) ([19d138e](https://github.com/OneBusAway/go-sdk/commit/19d138e89e3926508836ef3ff7cf6b7b95abef3f))


### Bug Fixes

* **client:** return error on bad custom url instead of panic ([#80](https://github.com/OneBusAway/go-sdk/issues/80)) ([70a742d](https://github.com/OneBusAway/go-sdk/commit/70a742db5646d7a6c7c5ded09029a1fe76c989b2))
* handle empty bodies in WithJSONSet ([f117b7d](https://github.com/OneBusAway/go-sdk/commit/f117b7d53c948c4b39f423a3bea6253db5883a9d))
* **test:** return early after test failure ([#78](https://github.com/OneBusAway/go-sdk/issues/78)) ([a3975d5](https://github.com/OneBusAway/go-sdk/commit/a3975d5cfc9c9323ae81c7be878459ce73eac1a0))


### Chores

* add request options to client tests ([#77](https://github.com/OneBusAway/go-sdk/issues/77)) ([a1409d6](https://github.com/OneBusAway/go-sdk/commit/a1409d69548e61a745a2ccaf308657ee43f1bfcb))
* **ci:** add timeout thresholds for CI jobs ([6c4e058](https://github.com/OneBusAway/go-sdk/commit/6c4e05895395d160766d8186a39b923398927d9d))
* **ci:** only use depot for staging repos ([27ea834](https://github.com/OneBusAway/go-sdk/commit/27ea83482c078d8cff0077f180289833a0b4c7f5))
* **docs:** document pre-request options ([1d1d81c](https://github.com/OneBusAway/go-sdk/commit/1d1d81c5d5b5fc251bcf6c23faaf17356a765e8c))
* **docs:** improve security documentation ([#76](https://github.com/OneBusAway/go-sdk/issues/76)) ([301ca94](https://github.com/OneBusAway/go-sdk/commit/301ca94a7f6f7925d76ce9031fc9733ccda4dfce))
* fix typos ([#79](https://github.com/OneBusAway/go-sdk/issues/79)) ([1b71db2](https://github.com/OneBusAway/go-sdk/commit/1b71db2b5d785c5657c8e2efed3202f562a941c8))
* **internal:** codegen related update ([db7e619](https://github.com/OneBusAway/go-sdk/commit/db7e619fd67b7365885ca9964ffaa61d52e984e1))
* **internal:** expand CI branch coverage ([39a0bd5](https://github.com/OneBusAway/go-sdk/commit/39a0bd532bd1884c5c0354cec004ec8be274732c))
* **internal:** reduce CI branch coverage ([dd831b8](https://github.com/OneBusAway/go-sdk/commit/dd831b8fa18ed73c2a8170cf428f63697cfbf675))
* **internal:** remove extra empty newlines ([#75](https://github.com/OneBusAway/go-sdk/issues/75)) ([b943deb](https://github.com/OneBusAway/go-sdk/commit/b943debfa05d346f776ea79477e83d6d382d81f5))


### Documentation

* update documentation links to be more uniform ([82d2142](https://github.com/OneBusAway/go-sdk/commit/82d21422f00dfe21f1562ea49406bc3671a9686e))


### Refactors

* tidy up dependencies ([#73](https://github.com/OneBusAway/go-sdk/issues/73)) ([d2fd02d](https://github.com/OneBusAway/go-sdk/commit/d2fd02d6c29f38cffaef48b61e50b3e34101daae))

## 0.1.0-alpha.23 (2025-03-01)

Full Changelog: [v0.1.0-alpha.22...v0.1.0-alpha.23](https://github.com/OneBusAway/go-sdk/compare/v0.1.0-alpha.22...v0.1.0-alpha.23)
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

<a href="https://pkg.go.dev/github.com/OneBusAway/go-sdk"><img src="https://pkg.go.dev/badge/github.com/OneBusAway/go-sdk.svg" alt="Go Reference"></a>

The Onebusaway SDK Go library provides convenient access to [the Onebusaway SDK REST
API](https://developer.onebusaway.org) from applications written in Go. The full API of this library can be found in [api.md](api.md).
The Onebusaway SDK Go library provides convenient access to the [Onebusaway SDK REST API](https://developer.onebusaway.org)
from applications written in Go.

It is generated with [Stainless](https://www.stainless.com/).

Expand All @@ -24,7 +24,7 @@ Or to pin the version:
<!-- x-release-please-start-version -->

```sh
go get -u 'github.com/OneBusAway/go-sdk@v0.1.0-alpha.23'
go get -u 'github.com/OneBusAway/go-sdk@v0.1.0-alpha.24'
```

<!-- x-release-please-end -->
Expand Down
21 changes: 15 additions & 6 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,25 @@ type Client struct {
Shape *ShapeService
}

// NewClient generates a new client with the default option read from the
// environment (ONEBUSAWAY_API_KEY). The option passed in as arguments are applied
// after these default arguments, and all option will be passed down to the
// services and requests that this client makes.
func NewClient(opts ...option.RequestOption) (r *Client) {
// DefaultClientOptions read from the environment (ONEBUSAWAY_API_KEY,
// ONEBUSAWAY_SDK_BASE_URL). This should be used to initialize new clients.
func DefaultClientOptions() []option.RequestOption {
defaults := []option.RequestOption{option.WithEnvironmentProduction()}
if o, ok := os.LookupEnv("ONEBUSAWAY_SDK_BASE_URL"); ok {
defaults = append(defaults, option.WithBaseURL(o))
}
if o, ok := os.LookupEnv("ONEBUSAWAY_API_KEY"); ok {
defaults = append(defaults, option.WithAPIKey(o))
}
opts = append(defaults, opts...)
return defaults
}

// NewClient generates a new client with the default option read from the
// environment (ONEBUSAWAY_API_KEY, ONEBUSAWAY_SDK_BASE_URL). The option passed in
// as arguments are applied after these default arguments, and all option will be
// passed down to the services and requests that this client makes.
func NewClient(opts ...option.RequestOption) (r *Client) {
opts = append(DefaultClientOptions(), opts...)

r = &Client{Options: opts}

Expand Down
8 changes: 8 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func (t *closureTransport) RoundTrip(req *http.Request) (*http.Response, error)
func TestUserAgentHeader(t *testing.T) {
var userAgent string
client := onebusaway.NewClient(
option.WithAPIKey("My API Key"),
option.WithHTTPClient(&http.Client{
Transport: &closureTransport{
fn: func(req *http.Request) (*http.Response, error) {
Expand All @@ -46,6 +47,7 @@ func TestUserAgentHeader(t *testing.T) {
func TestRetryAfter(t *testing.T) {
retryCountHeaders := make([]string, 0)
client := onebusaway.NewClient(
option.WithAPIKey("My API Key"),
option.WithHTTPClient(&http.Client{
Transport: &closureTransport{
fn: func(req *http.Request) (*http.Response, error) {
Expand Down Expand Up @@ -79,6 +81,7 @@ func TestRetryAfter(t *testing.T) {
func TestDeleteRetryCountHeader(t *testing.T) {
retryCountHeaders := make([]string, 0)
client := onebusaway.NewClient(
option.WithAPIKey("My API Key"),
option.WithHTTPClient(&http.Client{
Transport: &closureTransport{
fn: func(req *http.Request) (*http.Response, error) {
Expand Down Expand Up @@ -108,6 +111,7 @@ func TestDeleteRetryCountHeader(t *testing.T) {
func TestOverwriteRetryCountHeader(t *testing.T) {
retryCountHeaders := make([]string, 0)
client := onebusaway.NewClient(
option.WithAPIKey("My API Key"),
option.WithHTTPClient(&http.Client{
Transport: &closureTransport{
fn: func(req *http.Request) (*http.Response, error) {
Expand Down Expand Up @@ -137,6 +141,7 @@ func TestOverwriteRetryCountHeader(t *testing.T) {
func TestRetryAfterMs(t *testing.T) {
attempts := 0
client := onebusaway.NewClient(
option.WithAPIKey("My API Key"),
option.WithHTTPClient(&http.Client{
Transport: &closureTransport{
fn: func(req *http.Request) (*http.Response, error) {
Expand All @@ -162,6 +167,7 @@ func TestRetryAfterMs(t *testing.T) {

func TestContextCancel(t *testing.T) {
client := onebusaway.NewClient(
option.WithAPIKey("My API Key"),
option.WithHTTPClient(&http.Client{
Transport: &closureTransport{
fn: func(req *http.Request) (*http.Response, error) {
Expand All @@ -181,6 +187,7 @@ func TestContextCancel(t *testing.T) {

func TestContextCancelDelay(t *testing.T) {
client := onebusaway.NewClient(
option.WithAPIKey("My API Key"),
option.WithHTTPClient(&http.Client{
Transport: &closureTransport{
fn: func(req *http.Request) (*http.Response, error) {
Expand Down Expand Up @@ -208,6 +215,7 @@ func TestContextDeadline(t *testing.T) {

go func() {
client := onebusaway.NewClient(
option.WithAPIKey("My API Key"),
option.WithHTTPClient(&http.Client{
Transport: &closureTransport{
fn: func(req *http.Request) (*http.Response, error) {
Expand Down
8 changes: 5 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ module github.com/OneBusAway/go-sdk
go 1.21

require (
github.com/google/uuid v1.3.0 // indirect
github.com/tidwall/gjson v1.14.4 // indirect
github.com/tidwall/gjson v1.14.4
github.com/tidwall/sjson v1.2.5
)

require (
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
)
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
Expand Down
65 changes: 57 additions & 8 deletions internal/requestconfig/requestconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"io"
"math"
"math/rand"
"mime"
"net/http"
"net/url"
"runtime"
Expand All @@ -21,6 +22,7 @@ import (
"github.com/OneBusAway/go-sdk/internal/apierror"
"github.com/OneBusAway/go-sdk/internal/apiform"
"github.com/OneBusAway/go-sdk/internal/apiquery"
"github.com/OneBusAway/go-sdk/internal/param"
)

func getDefaultHeaders() map[string]string {
Expand Down Expand Up @@ -76,7 +78,17 @@ func getPlatformProperties() map[string]string {
}
}

func NewRequestConfig(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...func(*RequestConfig) error) (*RequestConfig, error) {
type RequestOption interface {
Apply(*RequestConfig) error
}

type RequestOptionFunc func(*RequestConfig) error
type PreRequestOptionFunc func(*RequestConfig) error

func (s RequestOptionFunc) Apply(r *RequestConfig) error { return s(r) }
func (s PreRequestOptionFunc) Apply(r *RequestConfig) error { return s(r) }

func NewRequestConfig(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...RequestOption) (*RequestConfig, error) {
var reader io.Reader

contentType := "application/json"
Expand Down Expand Up @@ -173,16 +185,30 @@ func NewRequestConfig(ctx context.Context, method string, u string, body interfa
return &cfg, nil
}

func UseDefaultParam[T any](dst *param.Field[T], src *T) {
if !dst.Present && src != nil {
dst.Value = *src
dst.Present = true
}
}

// This interface is primarily used to describe an [*http.Client], but also
// supports custom HTTP implementations.
type HTTPDoer interface {
Do(req *http.Request) (*http.Response, error)
}

// RequestConfig represents all the state related to one request.
//
// Editing the variables inside RequestConfig directly is unstable api. Prefer
// composing func(\*RequestConfig) error instead if possible.
// composing the RequestOption instead if possible.
type RequestConfig struct {
MaxRetries int
RequestTimeout time.Duration
Context context.Context
Request *http.Request
BaseURL *url.URL
CustomHTTPDoer HTTPDoer
HTTPClient *http.Client
Middlewares []middleware
APIKey string
Expand Down Expand Up @@ -222,7 +248,7 @@ func shouldRetry(req *http.Request, res *http.Response) bool {
return true
}

// If the header explictly wants a retry behavior, respect that over the
// If the header explicitly wants a retry behavior, respect that over the
// http status code.
if res.Header.Get("x-should-retry") == "true" {
return true
Expand Down Expand Up @@ -380,6 +406,9 @@ func (cfg *RequestConfig) Execute() (err error) {
}

handler := cfg.HTTPClient.Do
if cfg.CustomHTTPDoer != nil {
handler = cfg.CustomHTTPDoer.Do
}
for i := len(cfg.Middlewares) - 1; i >= 0; i -= 1 {
handler = applyMiddleware(cfg.Middlewares[i], handler)
}
Expand Down Expand Up @@ -485,7 +514,8 @@ func (cfg *RequestConfig) Execute() (err error) {

// If we are not json, return plaintext
contentType := res.Header.Get("content-type")
isJSON := strings.Contains(contentType, "application/json") || strings.Contains(contentType, "application/vnd.api+json")
mediaType, _, _ := mime.ParseMediaType(contentType)
isJSON := strings.Contains(mediaType, "application/json") || strings.HasSuffix(mediaType, "+json")
if !isJSON {
switch dst := cfg.ResponseBodyInto.(type) {
case *string:
Expand All @@ -496,7 +526,7 @@ func (cfg *RequestConfig) Execute() (err error) {
case *[]byte:
*dst = contents
default:
return fmt.Errorf("expected destination type of 'string' or '[]byte' for responses with content-type that is not 'application/json'")
return fmt.Errorf("expected destination type of 'string' or '[]byte' for responses with content-type '%s' that is not 'application/json'", contentType)
}
return nil
}
Expand All @@ -515,7 +545,7 @@ func (cfg *RequestConfig) Execute() (err error) {
return nil
}

func ExecuteNewRequest(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...func(*RequestConfig) error) error {
func ExecuteNewRequest(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...RequestOption) error {
cfg, err := NewRequestConfig(ctx, method, u, body, dst, opts...)
if err != nil {
return err
Expand Down Expand Up @@ -549,12 +579,31 @@ func (cfg *RequestConfig) Clone(ctx context.Context) *RequestConfig {
return new
}

func (cfg *RequestConfig) Apply(opts ...func(*RequestConfig) error) error {
func (cfg *RequestConfig) Apply(opts ...RequestOption) error {
for _, opt := range opts {
err := opt(cfg)
err := opt.Apply(cfg)
if err != nil {
return err
}
}
return nil
}

// PreRequestOptions is used to collect all the options which need to be known before
// a call to [RequestConfig.ExecuteNewRequest], such as path parameters
// or global defaults.
// PreRequestOptions will return a [RequestConfig] with the options applied.
//
// Only request option functions of type [PreRequestOptionFunc] are applied.
func PreRequestOptions(opts ...RequestOption) (RequestConfig, error) {
cfg := RequestConfig{}
for _, opt := range opts {
if opt, ok := opt.(PreRequestOptionFunc); ok {
err := opt.Apply(&cfg)
if err != nil {
return cfg, err
}
}
}
return cfg, nil
}
2 changes: 1 addition & 1 deletion internal/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

package internal

const PackageVersion = "0.1.0-alpha.23" // x-release-please-version
const PackageVersion = "0.1.0-alpha.24" // x-release-please-version
Loading