Author SHA1 Message Date
joe 1fd2dd50ce Add correlation_id to TransactionCreateRequest and TransactionHeader
Callers can set correlation_id when creating transactions to link
related transactions together (e.g. all transactions in a workflow).
The field propagates through the PRIME pipeline and child transactions.
2026-03-31 06:17:05 -05:00
amiller ee3c6941ee Added functions to get API partial credentials 2025-12-29 11:04:45 -05:00
amiller eb6100b736 Add context.Context parameter to all API methods
Enable request timeout and cancellation control by adding context.Context
as the first parameter to all SDK API methods. This allows users to:
- Set per-request timeouts
- Cancel in-flight requests
- Pass request-scoped values
2025-12-29 11:00:13 -05:00
9 changed files with 169 additions and 75 deletions
+29 -20
View File
@@ -14,8 +14,10 @@ go get git.dragonchain.com/dragonchain/dragonchain-prime-sdk-go
package main
import (
"context"
"fmt"
"log"
"time"
"git.dragonchain.com/dragonchain/dragonchain-prime-sdk-go"
"git.dragonchain.com/dragonchain/dragonchain-prime-sdk-go/models"
@@ -30,13 +32,17 @@ func main() {
"https://your-dragonchain-endpoint.com",
)
// Create a context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Check system health
if err := client.System.Health(); err != nil {
if err := client.System.Health(ctx); err != nil {
log.Fatal("Health check failed:", err)
}
// Get system status
status, err := client.System.Status()
status, err := client.System.Status(ctx)
if err != nil {
log.Fatal("Failed to get status:", err)
}
@@ -51,7 +57,7 @@ func main() {
Tag: "example-tag",
}
resp, err := client.Transaction.Create(txn)
resp, err := client.Transaction.Create(ctx, txn)
if err != nil {
log.Fatal("Failed to create transaction:", err)
}
@@ -61,31 +67,34 @@ func main() {
## Available Endpoints
All API methods accept a `context.Context` as their first parameter for timeout and cancellation control.
### System
- `Health()` - Check system health
- `Status()` - Get system status
- `Health(ctx)` - Check system health
- `Status(ctx)` - Get system status
### Transaction
- `Create(req)` - Create a new transaction
- `CreateBulk(req)` - Create multiple transactions
- `Get(transactionID)` - Get transaction by ID
- `Create(ctx, req)` - Create a new transaction
- `CreateBulk(ctx, req)` - Create multiple transactions
- `Get(ctx, transactionID)` - Get transaction by ID
- `List(ctx)` - List all transactions
### Transaction Type
- `Create(req)` - Create a new transaction type
- `Get(txnType)` - Get transaction type by name
- `List()` - List all transaction types
- `Delete(txnType)` - Delete a transaction type
- `Create(ctx, req)` - Create a new transaction type
- `Get(ctx, txnType)` - Get transaction type by name
- `List(ctx)` - List all transaction types
- `Delete(ctx, txnType)` - Delete a transaction type
### Smart Contract
- `Create(req)` - Create a new smart contract
- `Get(contractID)` - Get smart contract by ID
- `List()` - List all smart contracts
- `Update(contractID, req)` - Update a smart contract
- `Upload(contractID, req)` - Upload smart contract code
- `Delete(contractID)` - Delete a smart contract
- `Create(ctx, req)` - Create a new smart contract
- `Get(ctx, contractID)` - Get smart contract by ID
- `List(ctx)` - List all smart contracts
- `Update(ctx, contractID, req)` - Update a smart contract
- `Upload(ctx, contractID, filepath)` - Upload smart contract code
- `Delete(ctx, contractID)` - Delete a smart contract
### Block
- `Get(blockID)` - Get block by ID
- `Get(ctx, blockID)` - Get block by ID
## Authentication
@@ -93,4 +102,4 @@ The SDK uses HMAC-SHA256 authentication. You need to provide:
- `publicID` - Your Dragonchain public ID
- `authKeyID` - Your authentication key ID
- `authKey` - Your authentication key
- `baseURL` - The base URL of your Dragonchain node (e.g., "https://mychain.dragonchain.com")
- `baseURL` - The base URL of your Dragonchain node (e.g., "https://chains.dragonchain.com")
+3 -2
View File
@@ -1,6 +1,7 @@
package block
import (
"context"
"fmt"
"git.dragonchain.com/dragonchain/dragonchain-prime-sdk-go/client"
@@ -15,10 +16,10 @@ func NewBlockClient(c *client.Client) *BlockClient {
return &BlockClient{client: c}
}
func (bc *BlockClient) Get(blockID string) (*models.Block, error) {
func (bc *BlockClient) Get(ctx context.Context, blockID string) (*models.Block, error) {
var resp models.Block
path := fmt.Sprintf("/api/v1/block/%s", blockID)
err := bc.client.Get(path, &resp)
err := bc.client.Get(ctx, path, &resp)
if err != nil {
return nil, err
}
+27 -10
View File
@@ -2,6 +2,7 @@ package client
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
@@ -62,7 +63,7 @@ func (c *Client) createHmac(msgStr string) []byte {
return h.Sum(nil)
}
func (c *Client) doRequest(method, path, contentType string, body any, response any) error {
func (c *Client) doRequest(ctx context.Context, method, path, contentType string, body any, response any) error {
var bodyBytes []byte
var err error
@@ -83,7 +84,7 @@ func (c *Client) doRequest(method, path, contentType string, body any, response
}
fullURL := c.baseURL + path
req, err := http.NewRequest(method, fullURL, bytes.NewBuffer(bodyBytes))
req, err := http.NewRequestWithContext(ctx, method, fullURL, bytes.NewBuffer(bodyBytes))
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
@@ -127,18 +128,34 @@ func checkByteSlice(body interface{}) bool {
return ok
}
func (c *Client) Get(path string, response any) error {
return c.doRequest(http.MethodGet, path, "", nil, response)
func (c *Client) InternalId() string {
return c.publicID
}
func (c *Client) Post(path, contentType string, body any, response any) error {
return c.doRequest(http.MethodPost, path, contentType, body, response)
func (c *Client) PublicId() string {
return c.publicID
}
func (c *Client) Put(path, contentType string, body any, response any) error {
return c.doRequest(http.MethodPut, path, contentType, body, response)
func (c *Client) AuthKeyId() string {
return c.authKeyID
}
func (c *Client) Delete(path string, response any) error {
return c.doRequest(http.MethodDelete, path, "", nil, response)
func (c *Client) Endpoint() string {
return c.baseURL
}
func (c *Client) Get(ctx context.Context, path string, response any) error {
return c.doRequest(ctx, http.MethodGet, path, "", nil, response)
}
func (c *Client) Post(ctx context.Context, path, contentType string, body any, response any) error {
return c.doRequest(ctx, http.MethodPost, path, contentType, body, response)
}
func (c *Client) Put(ctx context.Context, path, contentType string, body any, response any) error {
return c.doRequest(ctx, http.MethodPut, path, contentType, body, response)
}
func (c *Client) Delete(ctx context.Context, path string, response any) error {
return c.doRequest(ctx, http.MethodDelete, path, "", nil, response)
}
+13 -12
View File
@@ -1,6 +1,7 @@
package contract
import (
"context"
"fmt"
"os"
@@ -16,45 +17,45 @@ func NewContractClient(c *client.Client) *ContractClient {
return &ContractClient{client: c}
}
func (cc *ContractClient) Create(req *models.SmartContractCreateRequest) (*models.SmartContract, error) {
func (cc *ContractClient) Create(ctx context.Context, req *models.SmartContractCreateRequest) (*models.SmartContract, error) {
var resp models.SmartContract
err := cc.client.Post("/api/v1/contract", models.ContentTypeJSON, req, &resp)
err := cc.client.Post(ctx, "/api/v1/contract", models.ContentTypeJSON, req, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func (cc *ContractClient) Get(contractID string) (*models.SmartContract, error) {
func (cc *ContractClient) Get(ctx context.Context, contractID string) (*models.SmartContract, error) {
var resp models.SmartContract
path := fmt.Sprintf("/api/v1/contract/%s", contractID)
err := cc.client.Get(path, &resp)
err := cc.client.Get(ctx, path, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func (cc *ContractClient) List() (*models.ListResponse, error) {
func (cc *ContractClient) List(ctx context.Context) (*models.ListResponse, error) {
var resp models.ListResponse
err := cc.client.Get("/api/v1/contract", &resp)
err := cc.client.Get(ctx, "/api/v1/contract", &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func (cc *ContractClient) Update(contractID string, req *models.SmartContractUpdateRequest) (*models.SuccessResponse, error) {
func (cc *ContractClient) Update(ctx context.Context, contractID string, req *models.SmartContractUpdateRequest) (*models.SuccessResponse, error) {
var resp models.SuccessResponse
path := fmt.Sprintf("/api/v1/contract/%s", contractID)
err := cc.client.Put(path, models.ContentTypeJSON, req, &resp)
err := cc.client.Put(ctx, path, models.ContentTypeJSON, req, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func (cc *ContractClient) Upload(contractID string, filepath string) (*models.SuccessResponse, error) {
func (cc *ContractClient) Upload(ctx context.Context, contractID string, filepath string) (*models.SuccessResponse, error) {
fileContent, err := os.ReadFile(filepath)
if err != nil {
return nil, fmt.Errorf("failed to read file: %w", err)
@@ -62,17 +63,17 @@ func (cc *ContractClient) Upload(contractID string, filepath string) (*models.Su
var resp models.SuccessResponse
path := fmt.Sprintf("/api/v1/contract/%s/upload", contractID)
err = cc.client.Put(path, "application/octet-stream", fileContent, &resp)
err = cc.client.Put(ctx, path, "application/octet-stream", fileContent, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func (cc *ContractClient) Delete(contractID string) (*models.SuccessResponse, error) {
func (cc *ContractClient) Delete(ctx context.Context, contractID string) (*models.SuccessResponse, error) {
var resp models.SuccessResponse
path := fmt.Sprintf("/api/v1/contract/%s", contractID)
err := cc.client.Delete(path, &resp)
err := cc.client.Delete(ctx, path, &resp)
if err != nil {
return nil, err
}
+60
View File
@@ -1,3 +1,49 @@
// Package sdk provides a Go SDK for interacting with Dragonchain nodes.
//
// All API methods require a context.Context parameter for timeout and cancellation control.
//
// Example usage:
//
// package main
//
// import (
// "context"
// "fmt"
// "log"
// "time"
//
// "git.dragonchain.com/dragonchain/dragonchain-prime-sdk-go"
// "git.dragonchain.com/dragonchain/dragonchain-prime-sdk-go/models"
// )
//
// func main() {
// client := sdk.NewDragonchainSDK(
// "your-public-id",
// "your-auth-key-id",
// "your-auth-key",
// "https://your-dragonchain-endpoint.com",
// )
//
// ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
// defer cancel()
//
// // Check system health
// if err := client.System.Health(ctx); err != nil {
// log.Fatal(err)
// }
//
// // Create a transaction
// txn := &models.TransactionCreateRequest{
// TxnType: "my-transaction-type",
// Payload: map[string]interface{}{"message": "Hello Dragonchain"},
// }
//
// resp, err := client.Transaction.Create(ctx, txn)
// if err != nil {
// log.Fatal(err)
// }
// fmt.Printf("Created transaction: %s\n", resp.TransactionID)
// }
package sdk
import (
@@ -9,6 +55,8 @@ import (
"git.dragonchain.com/dragonchain/dragonchain-prime-sdk-go/transactiontype"
)
// DragonchainSDK is the main SDK client for interacting with Dragonchain nodes.
// It provides access to all API endpoints through specialized client instances.
type DragonchainSDK struct {
client *client.Client
Transaction *transaction.TransactionClient
@@ -18,6 +66,16 @@ type DragonchainSDK struct {
System *system.SystemClient
}
// NewDragonchainSDK creates a new Dragonchain SDK client.
//
// Parameters:
// - publicID: Your Dragonchain public ID
// - authKeyID: Your authentication key ID
// - authKey: Your authentication key
// - baseURL: The base URL of your Dragonchain node (e.g., "https://mychain.dragonchain.com")
//
// Returns a configured SDK client ready to make API calls.
// All API methods on the returned client require a context.Context parameter.
func NewDragonchainSDK(publicID, authKeyID, authKey, baseURL string) *DragonchainSDK {
c := client.NewClient(publicID, authKeyID, authKey, baseURL)
return &DragonchainSDK{
@@ -30,6 +88,8 @@ func NewDragonchainSDK(publicID, authKeyID, authKey, baseURL string) *Dragonchai
}
}
// GetClient returns the underlying HTTP client used by the SDK.
// This can be useful for advanced use cases or custom implementations.
func (sdk *DragonchainSDK) GetClient() *client.Client {
return sdk.client
}
+13 -11
View File
@@ -5,10 +5,11 @@ const (
)
type TransactionCreateRequest struct {
Version string `json:"version,omitempty"`
TxnType string `json:"txn_type"`
Payload string `json:"payload"`
Tag string `json:"tag,omitempty"`
Version string `json:"version,omitempty"`
TxnType string `json:"txn_type"`
Payload string `json:"payload"`
Tag string `json:"tag,omitempty"`
CorrelationId string `json:"correlation_id,omitempty"`
}
type TransactionCreateResponse struct {
@@ -35,13 +36,14 @@ type Transaction struct {
}
type TransactionHeader struct {
Tag string `json:"tag"`
DcId string `json:"dc_id"`
TxnId string `json:"txn_id"`
Invoker string `json:"invoker"`
BlockId string `json:"block_id"`
TxnType string `json:"txn_type"`
Timestamp string `json:"timestamp"`
Tag string `json:"tag"`
DcId string `json:"dc_id"`
TxnId string `json:"txn_id"`
Invoker string `json:"invoker"`
BlockId string `json:"block_id"`
TxnType string `json:"txn_type"`
Timestamp string `json:"timestamp"`
CorrelationId string `json:"correlation_id,omitempty"`
}
type TransactionProof struct {
+6 -4
View File
@@ -1,6 +1,8 @@
package system
import (
"context"
"git.dragonchain.com/dragonchain/dragonchain-prime-sdk-go/client"
"git.dragonchain.com/dragonchain/dragonchain-prime-sdk-go/models"
)
@@ -13,13 +15,13 @@ func NewSystemClient(c *client.Client) *SystemClient {
return &SystemClient{client: c}
}
func (sc *SystemClient) Health() error {
return sc.client.Get("/api/v1/health", nil)
func (sc *SystemClient) Health(ctx context.Context) error {
return sc.client.Get(ctx, "/api/v1/health", nil)
}
func (sc *SystemClient) Status() (*models.SystemStatus, error) {
func (sc *SystemClient) Status(ctx context.Context) (*models.SystemStatus, error) {
var resp models.SystemStatus
err := sc.client.Get("/api/v1/status", &resp)
err := sc.client.Get(ctx, "/api/v1/status", &resp)
if err != nil {
return nil, err
}
+9 -8
View File
@@ -1,6 +1,7 @@
package transaction
import (
"context"
"fmt"
"git.dragonchain.com/dragonchain/dragonchain-prime-sdk-go/client"
@@ -15,38 +16,38 @@ func NewTransactionClient(c *client.Client) *TransactionClient {
return &TransactionClient{client: c}
}
func (tc *TransactionClient) Create(req *models.TransactionCreateRequest) (*models.TransactionCreateResponse, error) {
func (tc *TransactionClient) Create(ctx context.Context, req *models.TransactionCreateRequest) (*models.TransactionCreateResponse, error) {
var resp models.TransactionCreateResponse
err := tc.client.Post("/api/v1/transaction", models.ContentTypeJSON, req, &resp)
err := tc.client.Post(ctx, "/api/v1/transaction", models.ContentTypeJSON, req, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func (tc *TransactionClient) CreateBulk(req *models.TransactionBulkRequest) (*models.TransactionBulkResponse, error) {
func (tc *TransactionClient) CreateBulk(ctx context.Context, req *models.TransactionBulkRequest) (*models.TransactionBulkResponse, error) {
var resp models.TransactionBulkResponse
err := tc.client.Post("/api/v1/transaction/bulk", models.ContentTypeJSON, req, &resp)
err := tc.client.Post(ctx, "/api/v1/transaction/bulk", models.ContentTypeJSON, req, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func (tc *TransactionClient) Get(transactionID string) (*models.Transaction, error) {
func (tc *TransactionClient) Get(ctx context.Context, transactionID string) (*models.Transaction, error) {
var resp models.Transaction
path := fmt.Sprintf("/api/v1/transaction/%s", transactionID)
err := tc.client.Get(path, &resp)
err := tc.client.Get(ctx, path, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func (tc *TransactionClient) List() (*models.ListTransactionsResponse, error) {
func (tc *TransactionClient) List(ctx context.Context) (*models.ListTransactionsResponse, error) {
var resp models.ListTransactionsResponse
path := "/api/v1/transaction/"
err := tc.client.Get(path, &resp)
err := tc.client.Get(ctx, path, &resp)
if err != nil {
return nil, err
}
+9 -8
View File
@@ -1,6 +1,7 @@
package transactiontype
import (
"context"
"fmt"
"git.dragonchain.com/dragonchain/dragonchain-prime-sdk-go/client"
@@ -15,38 +16,38 @@ func NewTransactionTypeClient(c *client.Client) *TransactionTypeClient {
return &TransactionTypeClient{client: c}
}
func (ttc *TransactionTypeClient) Create(req *models.TransactionTypeCreateRequest) (*models.TransactionTypeCreateResponse, error) {
func (ttc *TransactionTypeClient) Create(ctx context.Context, req *models.TransactionTypeCreateRequest) (*models.TransactionTypeCreateResponse, error) {
var resp models.TransactionTypeCreateResponse
err := ttc.client.Post("/api/v1/transaction-type", models.ContentTypeJSON, req, &resp)
err := ttc.client.Post(ctx, "/api/v1/transaction-type", models.ContentTypeJSON, req, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func (ttc *TransactionTypeClient) Get(txnType string) (*models.TransactionType, error) {
func (ttc *TransactionTypeClient) Get(ctx context.Context, txnType string) (*models.TransactionType, error) {
var resp models.TransactionType
path := fmt.Sprintf("/api/v1/transaction-type/%s", txnType)
err := ttc.client.Get(path, &resp)
err := ttc.client.Get(ctx, path, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func (ttc *TransactionTypeClient) List() (*models.TransactionListResponse, error) {
func (ttc *TransactionTypeClient) List(ctx context.Context) (*models.TransactionListResponse, error) {
var resp models.TransactionListResponse
err := ttc.client.Get("/api/v1/transaction-types", &resp)
err := ttc.client.Get(ctx, "/api/v1/transaction-types", &resp)
if err != nil {
return nil, err
}
return &resp, nil
}
func (ttc *TransactionTypeClient) Delete(txnType string) (*models.SuccessResponse, error) {
func (ttc *TransactionTypeClient) Delete(ctx context.Context, txnType string) (*models.SuccessResponse, error) {
var resp models.SuccessResponse
path := fmt.Sprintf("/api/v1/transaction-type/%s", txnType)
err := ttc.client.Delete(path, &resp)
err := ttc.client.Delete(ctx, path, &resp)
if err != nil {
return nil, err
}