Skip to content

Commit 05f84ea

Browse files
Merge pull request #17 from speakeasy-api/feature/spe-369
feat: support getting embed access token
2 parents e6f83c3 + 1d6931e commit 05f84ea

24 files changed

+175
-61
lines changed

README.md

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ Build and deploy your app and that's it. Your API is being tracked in the Speake
5454
and will be visible on the dashboard next time you log in. Visit our [docs site](https://docs.speakeasyapi.dev/) to
5555
learn more.
5656

57-
5857
### Advanced configuration
5958

6059
The Speakeasy SDK provides both a global and per Api configuration option. If you want to use the SDK to track multiple Apis or Versions from the same service you can configure individual instances of the SDK, like so:
@@ -128,8 +127,6 @@ Wildcard path matching in Echo & Chi will end up with a OpenAPI path paramater c
128127

129128
And in the above example a path like `/user/1/path/some/sub/path` won't match but `/user/1/path/somesubpathstring` will, as `/` characters are not matched in path paramters by the OpenAPI spec.
130129

131-
132-
133130
## Capturing Customer IDs
134131

135132
To help associate requests with customers/users of your APIs you can provide a customer ID per request handler:
@@ -193,3 +190,55 @@ r.Use(func (next http.Handler) http.Handler {
193190
})
194191
})
195192
```
193+
194+
## Embedded Request Viewer Access Tokens
195+
196+
The Speakeasy SDK can generate access tokens for the [Embedded Request Viewer](https://docs.speakeasyapi.dev/speakeasy-user-guide/request-viewer/embedded-request-viewer) that can be used to view requests captured by the SDK.
197+
198+
For documentation on how to configure filters, find that [HERE](https://docs.speakeasyapi.dev/speakeasy-user-guide/request-viewer/embedded-request-viewer).
199+
200+
Below are some examples on how to generate access tokens:
201+
202+
```go
203+
import "github.com/speakeasy-api/speakeasy-schemas/grpc/go/registry/embedaccesstoken"
204+
205+
ctx := context.Background()
206+
207+
// If the SDK is configured as a global instance, an access token can be generated using the `GenerateAccessToken` function on the speakeasy package.
208+
accessToken, err := speakeasy.GetEmbedAccessToken(ctx, &embedaccesstoken.EmbedAccessTokenRequest{
209+
Filters: []*embedaccesstoken.EmbedAccessTokenRequest_Filter{
210+
{
211+
Key: "customer_id",
212+
Operator: "=",
213+
Value: "a-customer-id",
214+
},
215+
},
216+
})
217+
218+
// If you have followed the `Advanced Configuration` section above you can also generate an access token using the `GenerateAccessToken` function on the sdk instance.
219+
accessToken, err := storeSDKInstance.GetEmbedAccessToken(ctx, &embedaccesstoken.EmbedAccessTokenRequest{
220+
Filters: []*embedaccesstoken.EmbedAccessTokenRequest_Filter{
221+
{
222+
Key: "customer_id",
223+
Operator: "=",
224+
Value: "a-customer-id",
225+
},
226+
},
227+
})
228+
229+
// Or finally if you have a handler that you would like to generate an access token from, you can get the SDK instance for that handler from the middleware controller and use the `GetEmbedAccessToken` function it.
230+
func MyHandler(w http.ResponseWriter, r *http.Request) {
231+
ctrl := speakeasy.MiddlewareController(req)
232+
accessToken, err := ctrl.GetSDKInstance().GetEmbedAccessToken(ctx, &embedaccesstoken.EmbedAccessTokenRequest{
233+
Filters: []*embedaccesstoken.EmbedAccessTokenRequest_Filter{
234+
{
235+
Key: "customer_id",
236+
Operator: "=",
237+
Value: "a-customer-id",
238+
},
239+
},
240+
})
241+
242+
// the rest of your handlers code
243+
}
244+
```

capture.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func (s *Speakeasy) handleRequestResponseError(w http.ResponseWriter, r *http.Re
4949
r.Body = ioutil.NopCloser(tee)
5050
}
5151

52-
ctx, c := contextWithController(r.Context())
52+
ctx, c := contextWithController(r.Context(), s)
5353
r = r.WithContext(ctx)
5454

5555
err := next(cw.GetResponseWriter(), r)
@@ -83,7 +83,7 @@ func (s *Speakeasy) captureRequestResponse(cw *captureWriter, r *http.Request, s
8383
return
8484
}
8585

86-
s.sendToIngest(ctx, &ingest.IngestRequest{
86+
s.grpcClient.SendToIngest(ctx, &ingest.IngestRequest{
8787
Har: string(harData),
8888
PathHint: pathHint,
8989
ApiId: s.config.ApiID,

controller.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ type controller struct {
219219
responseCookieMasks map[string]string
220220
responseFieldMasksString map[string]string
221221
responseFieldMasksNumber map[string]string
222+
sdkInstance *Speakeasy
222223
}
223224

224225
// MiddlewareController will return the speakeasy middleware controller from the current request,
@@ -244,7 +245,11 @@ func (c *controller) Masking(opts ...MaskingOption) {
244245
}
245246
}
246247

247-
func contextWithController(ctx context.Context) (context.Context, *controller) {
248+
func (c *controller) GetSDKInstance() *Speakeasy {
249+
return c.sdkInstance
250+
}
251+
252+
func contextWithController(ctx context.Context, sdk *Speakeasy) (context.Context, *controller) {
248253
c := &controller{
249254
queryStringMasks: make(map[string]string),
250255
requestHeaderMasks: make(map[string]string),
@@ -255,6 +260,7 @@ func contextWithController(ctx context.Context) (context.Context, *controller) {
255260
responseCookieMasks: make(map[string]string),
256261
responseFieldMasksString: make(map[string]string),
257262
responseFieldMasksNumber: make(map[string]string),
263+
sdkInstance: sdk,
258264
}
259265
return context.WithValue(ctx, controllerKey, c), c
260266
}

controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func TestWithQueryStringMask(t *testing.T) {
8989
}
9090
for _, tt := range tests {
9191
t.Run(tt.name, func(t *testing.T) {
92-
_, c := contextWithController(context.Background())
92+
_, c := contextWithController(context.Background(), nil)
9393
c.Masking(WithQueryStringMask(tt.args.keys, tt.args.masks...))
9494
assert.Equal(t, tt.wantQueryStringMasks, c.queryStringMasks)
9595
})

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ require (
1313
github.com/go-chi/chi/v5 v5.0.7
1414
github.com/gorilla/mux v1.8.0
1515
github.com/labstack/echo/v4 v4.7.2
16-
github.com/speakeasy-api/speakeasy-schemas v1.2.0
16+
github.com/speakeasy-api/speakeasy-schemas v1.3.0
1717
go.uber.org/zap v1.21.0
1818
google.golang.org/grpc v1.48.0
1919
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA
117117
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
118118
github.com/speakeasy-api/speakeasy-schemas v1.2.0 h1:raBOAba2M3ll9Xdw8yuJohtukonm3r9NytQqMFCSlOY=
119119
github.com/speakeasy-api/speakeasy-schemas v1.2.0/go.mod h1:g6NfrOjYLCJZp81ZLY2ksF7afC9BW9bL4Bg1V1oAFlw=
120+
github.com/speakeasy-api/speakeasy-schemas v1.3.0 h1:7Arm2d0/K9owEBQPmNon1KPERmf58g0Eg/NmPgXaEY0=
121+
github.com/speakeasy-api/speakeasy-schemas v1.3.0/go.mod h1:g6NfrOjYLCJZp81ZLY2ksF7afC9BW9bL4Bg1V1oAFlw=
120122
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
121123
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
122124
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=

middleware.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ func Middleware(next http.Handler) http.Handler {
1919
// Middleware setups the current instance of the SDK to start capturing requests from routers that support http.Handlers.
2020
// Currently only gorilla/mux, go-chi/chi routers and the http.DefaultServerMux are supported for automatically
2121
// capturing path hints. Otherwise path hints can be supplied by a handler through the speakeasy MiddlewareController.
22+
//
23+
//nolint:contextcheck
2224
func (s *Speakeasy) Middleware(next http.Handler) http.Handler {
2325
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2426
s.handleRequestResponse(w, r, next.ServeHTTP, func(r *http.Request) string {

speakeasy.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"net"
88
"os"
99
"regexp"
10+
11+
"github.com/speakeasy-api/speakeasy-schemas/grpc/go/registry/embedaccesstoken"
1012
)
1113

1214
var (
@@ -27,7 +29,7 @@ const (
2729
)
2830

2931
var (
30-
speakeasyVersion = "1.2.0" // TODO get this from CI
32+
speakeasyVersion = "1.3.0" // TODO get this from CI
3133
serverURL = "grpc.prod.speakeasyapi.dev:443"
3234

3335
defaultInstance *Speakeasy
@@ -55,9 +57,8 @@ type Config struct {
5557
// Don't instantiate this directly, use Configure() or New() instead.
5658
type Speakeasy struct {
5759
config Config
58-
serverURL string
59-
secure bool
6060
harBuilder harBuilder
61+
grpcClient *GRPCClient
6162
}
6263

6364
// Configure allows you to configure the default instance of the Speakeasy SDK.
@@ -76,6 +77,14 @@ func New(config Config) *Speakeasy {
7677
return s
7778
}
7879

80+
func GetEmbedAccessToken(ctx context.Context, req *embedaccesstoken.EmbedAccessTokenRequest) (string, error) {
81+
return defaultInstance.GetEmbedAccessToken(ctx, req)
82+
}
83+
84+
func (s *Speakeasy) GetEmbedAccessToken(ctx context.Context, req *embedaccesstoken.EmbedAccessTokenRequest) (string, error) {
85+
return s.grpcClient.GetEmbedAccessToken(ctx, req)
86+
}
87+
7988
func (s *Speakeasy) configure(cfg Config) {
8089
mustValidateConfig(cfg)
8190

@@ -96,10 +105,9 @@ func (s *Speakeasy) configure(cfg Config) {
96105
secure = false
97106
}
98107

99-
s.serverURL = configuredServerURL
100-
s.secure = secure
101-
102108
s.config = cfg
109+
110+
s.grpcClient = newGRPCClient(s.config.APIKey, configuredServerURL, secure, s.config.GRPCDialer)
103111
}
104112

105113
func mustValidateConfig(cfg Config) {

speakeasy_exports_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ func (s *Speakeasy) ExportGetSpeakeasyConfig() Config {
99
}
1010

1111
func (s *Speakeasy) ExportGetSpeakeasyServerURL() string {
12-
return s.serverURL
12+
return s.grpcClient.serverURL
1313
}
1414

1515
func (s *Speakeasy) ExportGetSpeakeasyServerSecure() bool {
16-
return s.secure
16+
return s.grpcClient.secure
1717
}

testdata/captures_basic_request_and_no_response_body_output.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "1.2",
44
"creator": {
55
"name": "speakeasy-go-sdk",
6-
"version": "1.2.0"
6+
"version": "1.3.0"
77
},
88
"entries": [
99
{

0 commit comments

Comments
 (0)