-
Notifications
You must be signed in to change notification settings - Fork 459
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
raw_request.Client + V2 UBB Examples (#1929)
* added rawrequest.Client type and associated functions, to let us specify a backend and key with which to make raw requests * added GetRawRequestBackend helper function to stripe, to get back a RawRequestBackend or error * added MeterEventsBackend and MeterEventsURL to constants, and added MeterEventsBackend to GetBackendWithConfig switch statement * added UBB examples
- Loading branch information
1 parent
1ba5c95
commit c4e7524
Showing
5 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"os" | ||
"time" | ||
|
||
stripe "github.com/stripe/stripe-go/v80" | ||
rawrequest "github.com/stripe/stripe-go/v80/rawrequest" | ||
) | ||
|
||
var sessionAuthToken string = "" | ||
var sessionAuthExpiresAt string = "" | ||
|
||
func refreshMeterEventSession(client rawrequest.Client) (err error) { | ||
currentTime := time.Now().Format(time.RFC3339) | ||
// Check if session is null or expired | ||
if sessionAuthToken == "" || sessionAuthExpiresAt <= currentTime { | ||
// Create a new meter event session in case the existing session expired | ||
rawResp, err := client.RawRequest(http.MethodPost, "/v2/billing/meter_event_session", "", nil) | ||
if err != nil { | ||
return err | ||
} | ||
if rawResp.StatusCode != 200 { | ||
return fmt.Errorf(rawResp.Status) | ||
} | ||
|
||
var resp map[string]interface{} | ||
err = json.Unmarshal(rawResp.RawJSON, &resp) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
sessionAuthToken = resp["authentication_token"].(string) | ||
sessionAuthExpiresAt = resp["expires_at"].(string) | ||
|
||
fmt.Println("Meter event session created!") | ||
} | ||
return nil | ||
} | ||
|
||
func sendMeterEvent(client rawrequest.Client, eventName string, stripeCustomerID string, value string) (err error) { | ||
// Refresh the meter event session if necessary | ||
refreshMeterEventSession(client) | ||
|
||
if sessionAuthToken == "" { | ||
err = fmt.Errorf("Unable to refresh meter event session") | ||
return | ||
} | ||
|
||
b, err := stripe.GetRawRequestBackend(stripe.MeterEventsBackend) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
sessionClient := rawrequest.Client{B: b, Key: sessionAuthToken} | ||
|
||
params := map[string]interface{}{ | ||
"events": []interface{}{ | ||
map[string]interface{}{ | ||
"event_name": eventName, | ||
"payload": map[string]interface{}{ | ||
"stripe_customer_id": stripeCustomerID, | ||
"value": value, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
contentBytes, err := json.Marshal(params) | ||
if err != nil { | ||
return | ||
} | ||
|
||
content := string(contentBytes) | ||
_, err = sessionClient.RawRequest(http.MethodPost, "/v2/billing/meter_event_stream", content, nil) | ||
return | ||
} | ||
|
||
func main() { | ||
|
||
apiKey := "{{API_KEY}}" | ||
customerID := "{{CUSTOMER_ID}}" | ||
|
||
b, err := stripe.GetRawRequestBackend(stripe.APIBackend) | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
|
||
client := rawrequest.Client{B: b, Key: apiKey} | ||
|
||
err = sendMeterEvent(client, "api_requests", customerID, "25") | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
fmt.Println("Meter event sent successfully!") | ||
} |
95 changes: 95 additions & 0 deletions
95
example/v2/thinevent_webhook_handler/thinevent_webhook_handler.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"os" | ||
|
||
"github.com/stripe/stripe-go/v80" | ||
billingMeters "github.com/stripe/stripe-go/v80/billing/meter" | ||
"github.com/stripe/stripe-go/v80/rawrequest" | ||
webhook "github.com/stripe/stripe-go/v80/webhook" | ||
) | ||
|
||
var apiKey = "{{API_KEY}}" | ||
var webhookSecret = "{{WEBHOOK_SECRET}}" | ||
|
||
func main() { | ||
b, err := stripe.GetRawRequestBackend(stripe.APIBackend) | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
|
||
client := rawrequest.Client{B: b, Key: apiKey} | ||
|
||
http.HandleFunc("/webhook", func(w http.ResponseWriter, req *http.Request) { | ||
const MaxBodyBytes = int64(65536) | ||
req.Body = http.MaxBytesReader(w, req.Body, MaxBodyBytes) | ||
payload, err := ioutil.ReadAll(req.Body) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err) | ||
w.WriteHeader(http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
err = webhook.ValidatePayload(payload, req.Header.Get("Stripe-Signature"), webhookSecret) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err) | ||
w.WriteHeader(http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
var thinEvent map[string]interface{} | ||
|
||
if err := json.Unmarshal(payload, &thinEvent); err != nil { | ||
fmt.Fprintf(os.Stderr, "Failed to parse thin event body json: %v\n", err.Error()) | ||
w.WriteHeader(http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
eventID := thinEvent["id"].(string) | ||
|
||
var event map[string]interface{} | ||
|
||
resp, err := client.RawRequest(http.MethodGet, "/v2/core/events/"+eventID, "", nil) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Failed to get pull event: %v\n", err.Error()) | ||
w.WriteHeader(http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
if err := json.Unmarshal(resp.RawJSON, &event); err != nil { | ||
fmt.Fprintf(os.Stderr, "Failed to parse pull event body json: %v\n", err.Error()) | ||
w.WriteHeader(http.StatusInternalServerError) | ||
return | ||
} | ||
// Unmarshal the event data into an appropriate struct depending on its Type | ||
switch t := event["type"].(string); t { | ||
case "v1.billing.meter.error_report_triggered": | ||
relatedObject := event["related_object"].(map[string]interface{}) | ||
meter, err := billingMeters.Get(relatedObject["id"].(string), nil) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Failed to get related meter object: %v\n", err.Error()) | ||
w.WriteHeader(http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
meterID := meter.ID | ||
fmt.Printf("Success! %s\n", meterID) | ||
// Verify we can see event data | ||
fmt.Println(fmt.Sprint(event["data"])) | ||
default: | ||
fmt.Fprintf(os.Stderr, "Unhandled event type: %s\n", t) | ||
} | ||
|
||
w.WriteHeader(http.StatusOK) | ||
}) | ||
err = http.ListenAndServe(":4242", nil) | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters