Back to Examples

Go

Integrate GuardCrow into your Go applications using the standard library or popular HTTP clients.

Basic Example

A simple example using the standard net/http package:

main.gogo
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
type AnalyzeRequest struct {
Content string `json:"content"`
Metadata map[string]string `json:"metadata,omitempty"`
}
type AnalyzeResponse struct {
Passed bool `json:"passed"`
Score int `json:"score"`
Sentiment string `json:"sentiment"`
Description string `json:"description"`
Categories []string `json:"categories"`
ProcessingTimeMs int `json:"processingTimeMs"`
}
func analyzeContent(content string) (*AnalyzeResponse, error) {
apiKey := os.Getenv("GUARDCROW_API_KEY")
reqBody := AnalyzeRequest{Content: content}
jsonBody, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}
req, err := http.NewRequest(
"POST",
"https://api.guardcrow.com/v1/analyze",
bytes.NewBuffer(jsonBody),
)
if err != nil {
return nil, err
}
req.Header.Set("X-API-Key", apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result AnalyzeResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
return &result, nil
}
func main() {
result, err := analyzeContent("Hello, this is a test message")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Passed: %v, Score: %d\n", result.Passed, result.Score)
}

Complete Client Package

A production-ready client with retry logic and error handling:

guardcrow/client.gogo
package guardcrow
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strconv"
"time"
)
var (
ErrRateLimited = errors.New("rate limit exceeded")
ErrInvalidAPIKey = errors.New("invalid API key")
ErrContentTooLong = errors.New("content exceeds maximum length")
)
type Client struct {
apiKey string
baseURL string
httpClient *http.Client
maxRetries int
}
type ClientOption func(*Client)
func WithBaseURL(url string) ClientOption {
return func(c *Client) { c.baseURL = url }
}
func WithHTTPClient(client *http.Client) ClientOption {
return func(c *Client) { c.httpClient = client }
}
func WithMaxRetries(n int) ClientOption {
return func(c *Client) { c.maxRetries = n }
}
func NewClient(apiKey string, opts ...ClientOption) *Client {
c := &Client{
apiKey: apiKey,
baseURL: "https://api.guardcrow.com/v1",
httpClient: &http.Client{Timeout: 30 * time.Second},
maxRetries: 3,
}
for _, opt := range opts {
opt(c)
}
return c
}
type AnalyzeRequest struct {
Content string `json:"content"`
Metadata map[string]string `json:"metadata,omitempty"`
}
type AnalyzeResponse struct {
Passed bool `json:"passed"`
Score int `json:"score"`
Sentiment string `json:"sentiment"`
Description string `json:"description"`
Categories []string `json:"categories"`
ProcessingTimeMs int `json:"processingTimeMs"`
}
type APIError struct {
Code string `json:"code"`
Message string `json:"message"`
Status int `json:"status"`
}
func (e *APIError) Error() string {
return fmt.Sprintf("%s: %s", e.Code, e.Message)
}
func (c *Client) Analyze(ctx context.Context, req *AnalyzeRequest) (*AnalyzeResponse, error) {
var lastErr error
for attempt := 0; attempt < c.maxRetries; attempt++ {
result, err := c.doAnalyze(ctx, req)
if err == nil {
return result, nil
}
// Don't retry on certain errors
if errors.Is(err, ErrInvalidAPIKey) || errors.Is(err, ErrContentTooLong) {
return nil, err
}
lastErr = err
// Exponential backoff
if attempt < c.maxRetries-1 {
backoff := time.Duration(1<<attempt) * time.Second
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-time.After(backoff):
}
}
}
return nil, lastErr
}
func (c *Client) doAnalyze(ctx context.Context, req *AnalyzeRequest) (*AnalyzeResponse, error) {
jsonBody, err := json.Marshal(req)
if err != nil {
return nil, err
}
httpReq, err := http.NewRequestWithContext(
ctx,
"POST",
c.baseURL+"/analyze",
bytes.NewBuffer(jsonBody),
)
if err != nil {
return nil, err
}
httpReq.Header.Set("X-API-Key", c.apiKey)
httpReq.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(httpReq)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
switch resp.StatusCode {
case http.StatusOK:
var result AnalyzeResponse
if err := json.Unmarshal(body, &result); err != nil {
return nil, err
}
return &result, nil
case http.StatusTooManyRequests:
resetTime := resp.Header.Get("X-RateLimit-Reset")
if resetTime != "" {
if ts, err := strconv.ParseInt(resetTime, 10, 64); err == nil {
waitDuration := time.Until(time.Unix(ts, 0))
time.Sleep(waitDuration)
}
}
return nil, ErrRateLimited
case http.StatusUnauthorized:
return nil, ErrInvalidAPIKey
case http.StatusBadRequest:
var errResp struct {
Error APIError `json:"error"`
}
json.Unmarshal(body, &errResp)
if errResp.Error.Code == "CONTENT_TOO_LONG" {
return nil, ErrContentTooLong
}
return nil, &errResp.Error
default:
var errResp struct {
Error APIError `json:"error"`
}
if err := json.Unmarshal(body, &errResp); err != nil {
return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode)
}
return nil, &errResp.Error
}
}
func (c *Client) HealthCheck(ctx context.Context) (bool, error) {
req, err := http.NewRequestWithContext(ctx, "GET", c.baseURL+"/health", nil)
if err != nil {
return false, err
}
resp, err := c.httpClient.Do(req)
if err != nil {
return false, err
}
defer resp.Body.Close()
return resp.StatusCode == http.StatusOK, nil
}

Using the Client

main.gogo
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"yourproject/guardcrow"
)
func main() {
client := guardcrow.NewClient(
os.Getenv("GUARDCROW_API_KEY"),
guardcrow.WithMaxRetries(3),
)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
result, err := client.Analyze(ctx, &guardcrow.AnalyzeRequest{
Content: "This is a test message to analyze",
Metadata: map[string]string{
"source": "user-comments",
"user_id": "user_123",
},
})
if err != nil {
log.Fatal("Analysis failed:", err)
}
fmt.Printf("Passed: %v\n", result.Passed)
fmt.Printf("Score: %d\n", result.Score)
fmt.Printf("Sentiment: %s\n", result.Sentiment)
fmt.Printf("Description: %s\n", result.Description)
}

HTTP Middleware

Create middleware to automatically moderate incoming requests:

middleware.gogo
package middleware
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"yourproject/guardcrow"
)
type contextKey string
const ModerationResultKey contextKey = "moderation_result"
func ContentModeration(client *guardcrow.Client, contentField string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Only moderate POST/PUT/PATCH requests
if r.Method != "POST" && r.Method != "PUT" && r.Method != "PATCH" {
next.ServeHTTP(w, r)
return
}
// Read and restore body
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request", http.StatusBadRequest)
return
}
r.Body = io.NopCloser(bytes.NewBuffer(body))
// Extract content field
var data map[string]interface{}
if err := json.Unmarshal(body, &data); err != nil {
next.ServeHTTP(w, r)
return
}
content, ok := data[contentField].(string)
if !ok || content == "" {
next.ServeHTTP(w, r)
return
}
// Analyze content
result, err := client.Analyze(r.Context(), &guardcrow.AnalyzeRequest{
Content: content,
})
if err != nil {
// Don't block on API errors
next.ServeHTTP(w, r)
return
}
// Block toxic content
if result.Score >= 7 {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"error": "Content blocked by moderation",
"reason": result.Description,
})
return
}
// Add result to context for downstream handlers
ctx := context.WithValue(r.Context(), ModerationResultKey, result)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
// Helper to get moderation result from context
func GetModerationResult(ctx context.Context) *guardcrow.AnalyzeResponse {
result, _ := ctx.Value(ModerationResultKey).(*guardcrow.AnalyzeResponse)
return result
}

Gin Framework Example

main.gogo
package main
import (
"net/http"
"os"
"github.com/gin-gonic/gin"
"yourproject/guardcrow"
)
var csClient *guardcrow.Client
func init() {
csClient = guardcrow.NewClient(os.Getenv("GUARDCROW_API_KEY"))
}
type CommentRequest struct {
Content string `json:"content" binding:"required"`
UserID string `json:"user_id" binding:"required"`
}
func moderateMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
var req CommentRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
c.Abort()
return
}
result, err := csClient.Analyze(c.Request.Context(), &guardcrow.AnalyzeRequest{
Content: req.Content,
})
if err != nil {
// Log error but don't block
c.Set("moderation_error", err)
c.Next()
return
}
if result.Score >= 7 {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Content blocked",
"reason": result.Description,
})
c.Abort()
return
}
c.Set("moderation_result", result)
c.Set("comment_request", req)
c.Next()
}
}
func main() {
r := gin.Default()
r.POST("/comments", moderateMiddleware(), func(c *gin.Context) {
req := c.MustGet("comment_request").(CommentRequest)
result := c.MustGet("moderation_result").(*guardcrow.AnalyzeResponse)
// Save comment with moderation info
c.JSON(http.StatusCreated, gin.H{
"message": "Comment created",
"moderation_score": result.Score,
})
})
r.Run(":8080")
}

Environment Setup

Set your API key as an environment variable:

Terminalbash
export GUARDCROW_API_KEY=sk_live_your_api_key_here