Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .fern/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"packageName": "square",
"enableWireTests": true
},
"sdkVersion": "v3.1.0"
"sdkVersion": "v3.2.0"
}
5 changes: 5 additions & 0 deletions .fernignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ verify_signature.go
webhooks/client/verify_signature.go
webhooks/client/verify_signature_test.go

# Custom Reporting API polling helper. (The live reporting integration test
# lives under integration_tests/, already preserved above.)
reporting/load_and_wait.go
reporting/load_and_wait_test.go

# Aliases to preserve backwards compatibility.
alias.go
bookings/alias.go
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ jobs:
integration:
env:
TEST_SQUARE_TOKEN: ${{ secrets.TEST_SQUARE_TOKEN }}
TEST_SQUARE_REPORTING: ${{ secrets.TEST_SQUARE_REPORTING }}
runs-on: ubuntu-latest
steps:
- name: Checkout repo
Expand Down
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,43 @@ if err != nil {
}
```

## Reporting API

The [Reporting API](https://developer.squareup.com/docs/reporting-api/overview) is asynchronous: a
query sent to `client.Reporting.Load` that is still being computed comes back as an HTTP 200 whose
body is `{"error": "Continue wait"}` rather than the results. Callers are expected to re-send the
identical request, with backoff, until real results arrive.

The SDK provides `client.Reporting.LoadAndWait`, which owns that polling loop for you (exponential
backoff, defaults: 20 attempts, 2s → 20s, factor 2) and returns the resolved `*square.LoadResponse`.
Discover the queryable schema first with `client.Reporting.GetMetadata`.

```go
// Discover the cubes, measures, and dimensions you can query.
metadata, err := client.Reporting.GetMetadata(context.TODO())
if err != nil {
return err
}

// Run a query and transparently poll until it resolves.
response, err := client.Reporting.LoadAndWait(
context.TODO(),
&square.LoadRequest{
Query: &square.Query{
Measures: []string{"Orders.count"},
},
},
nil, // *reporting.LoadAndWaitOptions — pass nil for the defaults.
)
if err != nil {
return err
}
```

Tune the polling loop by passing a `*reporting.LoadAndWaitOptions` (any unset field falls back to its
default), and cancel it by cancelling the `context.Context`. The plain `client.Reporting.Load` call
remains available if you want to own the retry loop yourself.

## Advanced

### Request Options
Expand Down
3 changes: 3 additions & 0 deletions client/client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions core/request_option.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

110 changes: 110 additions & 0 deletions integration_tests/reporting_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//go:build integration

package integration

import (
"context"
"os"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

square "github.com/square/square-go-sdk/v3"
client "github.com/square/square-go-sdk/v3/client"
option "github.com/square/square-go-sdk/v3/option"
reporting "github.com/square/square-go-sdk/v3/reporting"
)

// Reporting API live integration tests.
//
// The Reporting API is a beta, bespoke offering served ONLY from production
// (connect.squareup.com/reporting) — it is not routed on sandbox (returns 404
// there). Validating it live therefore needs a production, reporting-provisioned
// token. The repo's other integration tests use TEST_SQUARE_TOKEN against
// sandbox (which 401s against prod), so this suite is gated behind — and
// authenticates with — TEST_SQUARE_REPORTING, the production,
// reporting-provisioned access token. It skips by default when that is unset,
// keeping CI green. The endpoints are read-only (schema discovery + queries).
// The polling *logic* is covered without a live account in
// reporting/load_and_wait_test.go.
//
// Run it against a real prod account:
//
// TEST_SQUARE_REPORTING=<prod-reporting-token> \
// go test ./integration_tests/... -tags=integration -run TestReportingAPI -v
// # override the host with TEST_SQUARE_BASE_URL=<url> if reporting moves.
func TestReportingAPI(t *testing.T) {
token := os.Getenv("TEST_SQUARE_REPORTING")
if token == "" {
t.Skip("set TEST_SQUARE_REPORTING=<prod-reporting-token> to run the live reporting suite")
}

// Reporting only exists on production; allow overriding the host via TEST_SQUARE_BASE_URL.
baseURL := os.Getenv("TEST_SQUARE_BASE_URL")
if baseURL == "" {
baseURL = square.Environments.Production
}
// Make the live target unambiguous in the test output (useful when triaging CI).
t.Logf("[reporting] base URL: %s -> %s/reporting/v1/{meta,load}", baseURL, baseURL)

squareClient := client.NewClient(
option.WithToken(token),
option.WithBaseURL(baseURL),
)
ctx := context.Background()

// firstMeasureName resolves the first queryable measure from the live schema,
// e.g. "Orders.count".
firstMeasureName := func(t *testing.T) string {
metadata, err := squareClient.Reporting.GetMetadata(ctx)
require.NoError(t, err)
require.NotEmpty(t, metadata.GetCubes(), "no cubes are available on the reporting schema for this account")
measures := metadata.GetCubes()[0].GetMeasures()
require.NotEmpty(t, measures, "the first cube exposes no measures")
return measures[0].GetName()
}

t.Run("GetMetadata returns the queryable schema (cubes + measures)", func(t *testing.T) {
metadata, err := squareClient.Reporting.GetMetadata(ctx)
require.NoError(t, err)
assert.NotEmpty(t, metadata.GetCubes())
})

t.Run("Load returns either results or the 'Continue wait' sentinel for an in-flight query", func(t *testing.T) {
measure := firstMeasureName(t)
response, err := squareClient.Reporting.Load(ctx, &square.LoadRequest{
Query: &square.Query{Measures: []string{measure}},
})
require.NoError(t, err)

if sentinel, ok := response.GetExtraProperties()["error"].(string); ok {
// Documented async behavior: a still-processing query comes back as HTTP 200
// with { "error": "Continue wait" } instead of results.
assert.Equal(t, "Continue wait", sentinel)
} else {
assert.NotNil(t, response.GetResults())
}
})

t.Run("LoadAndWait resolves a query end-to-end without surfacing 'Continue wait'", func(t *testing.T) {
measure := firstMeasureName(t)

// Polling can take minutes; bound it with a context deadline.
ctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
defer cancel()

response, err := squareClient.Reporting.LoadAndWait(
ctx,
&square.LoadRequest{Query: &square.Query{Measures: []string{measure}}},
&reporting.LoadAndWaitOptions{MaxAttempts: 20, InitialDelay: 2 * time.Second, MaxDelay: 20 * time.Second},
)
require.NoError(t, err)

// The polling helper must never hand back the raw "Continue wait" sentinel.
_, hasError := response.GetExtraProperties()["error"]
assert.False(t, hasError)
assert.NotNil(t, response.GetResults())
})
}
118 changes: 118 additions & 0 deletions reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -17454,6 +17454,124 @@ client.Vendors.Update(
</dl>


</dd>
</dl>
</details>

## Reporting
<details><summary><code>client.Reporting.GetMetadata() -> *square.MetadataResponse</code></summary>
<dl>
<dd>

#### 📝 Description

<dl>
<dd>

<dl>
<dd>

Describes the data available to query: the cubes, views, measures, dimensions, and segments you can reference in a reporting query. Call this first to discover the schema, then pass the members you need to `load`.
</dd>
</dl>
</dd>
</dl>

#### 🔌 Usage

<dl>
<dd>

<dl>
<dd>

```go
client.Reporting.GetMetadata(
context.TODO(),
)
}
```
</dd>
</dl>
</dd>
</dl>


</dd>
</dl>
</details>

<details><summary><code>client.Reporting.Load(request) -> *square.LoadResponse</code></summary>
<dl>
<dd>

#### 📝 Description

<dl>
<dd>

<dl>
<dd>

Runs a reporting query against the discovered schema and returns the aggregated results. Long-running queries may return a "Continue wait" response while processing — retry the same request until results are ready.
</dd>
</dl>
</dd>
</dl>

#### 🔌 Usage

<dl>
<dd>

<dl>
<dd>

```go
request := &square.LoadRequest{}
client.Reporting.Load(
context.TODO(),
request,
)
}
```
</dd>
</dl>
</dd>
</dl>

#### ⚙️ Parameters

<dl>
<dd>

<dl>
<dd>

**queryType:** `*string`

</dd>
</dl>

<dl>
<dd>

**cache:** `*square.CacheMode`

</dd>
</dl>

<dl>
<dd>

**query:** `*square.Query`

</dd>
</dl>
</dd>
</dl>


</dd>
</dl>
</details>
Expand Down
Loading
Loading