← Files CrowdStrike Falcon FoundryARCHIVED FILE
skills/functions-development/references/go-patterns.md
6.63 KB · Oct 2, 2026 · 00:31 UTC
# Go Function Patterns Reference
> Parent skill: [functions-development](../SKILL.md)
## FDK Handler with Configuration
Load configuration from `config.json` or `config.yaml` in the function directory:
```go
func newHandler(_ context.Context, _ *slog.Logger, cfg myConfig) fdk.Handler {
// cfg is loaded from config.json or config.yaml in the function directory
m := fdk.NewMux()
// ... use cfg in handlers
return m
}
```
## Alerts Handler with Falcon Client Auth and Response Helpers
Full alerts handler using `PostCombinedAlertsV1` (query + get in one call). Uses the concrete gofalcon response types rather than `interface{}`, and checks `Payload.Errors` the way the SDK examples do:
```go
// functions/alerts/main.go
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"os"
"github.com/crowdstrike/gofalcon/falcon"
"github.com/crowdstrike/gofalcon/falcon/client"
"github.com/crowdstrike/gofalcon/falcon/client/alerts"
"github.com/crowdstrike/gofalcon/falcon/models"
fdk "github.com/CrowdStrike/foundry-fn-go"
)
// Response structures
type APIResponse struct {
Data interface{} `json:"data,omitempty"`
Error *APIError `json:"error,omitempty"`
Status int `json:"status"`
}
type APIError struct {
Code string `json:"code"`
Message string `json:"message"`
}
// Handler is the main entry point
func Handler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if r.Method != http.MethodGet {
respondError(w, http.StatusMethodNotAllowed, "METHOD_NOT_ALLOWED", "Only GET method is supported")
return
}
accessToken := r.Header.Get("X-CS-ACCESSTOKEN")
opts := fdk.FalconClientOpts()
falconClient, err := falcon.NewClient(&falcon.ApiConfig{
AccessToken: accessToken,
Cloud: falcon.Cloud(opts.Cloud),
Context: ctx,
UserAgentOverride: opts.UserAgent,
})
if err != nil {
respondError(w, http.StatusInternalServerError, "AUTH_FAILED",
fmt.Sprintf("Failed to authenticate: %s", falcon.ErrorExplain(err)))
return
}
alertsData, err := fetchAlerts(ctx, falconClient, r)
if err != nil {
respondError(w, http.StatusInternalServerError, "FETCH_FAILED", err.Error())
return
}
respondSuccess(w, alertsData)
}
func fetchAlerts(ctx context.Context, c *client.CrowdStrikeAPISpecification, r *http.Request) (interface{}, error) {
limit := int64(50)
if l := r.URL.Query().Get("limit"); l != "" {
fmt.Sscanf(l, "%d", &limit)
if limit > 100 {
limit = 100
}
}
filter := `product:'detections'`
params := alerts.NewPostCombinedAlertsV1Params().
WithContext(ctx).
WithBody(&models.DetectsapiPostCombinedAlertsV1Request{
Filter: filter,
Limit: limit,
})
resp, err := c.Alerts.PostCombinedAlertsV1(params)
if err != nil {
return nil, fmt.Errorf("failed to query alerts: %s", falcon.ErrorExplain(err))
}
if err = falcon.AssertNoError(resp.Payload.Errors); err != nil {
return nil, fmt.Errorf("API returned errors: %w", err)
}
return resp.Payload.Resources, nil
}
func respondSuccess(w http.ResponseWriter, data interface{}) {
response := APIResponse{
Data: data,
Status: http.StatusOK,
}
writeJSON(w, http.StatusOK, response)
}
func respondError(w http.ResponseWriter, status int, code, message string) {
response := APIResponse{
Error: &APIError{
Code: code,
Message: message,
},
Status: status,
}
writeJSON(w, status, response)
}
func writeJSON(w http.ResponseWriter, status int, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
func main() {
http.HandleFunc("/", Handler)
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
http.ListenAndServe(":"+port, nil)
}
```
## Collection CRUD Pattern
Incident store using `custom_storage` for create, read, and delete operations:
```go
// functions/incidents/collection.go
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"time"
"github.com/crowdstrike/gofalcon/falcon"
"github.com/crowdstrike/gofalcon/falcon/client"
"github.com/crowdstrike/gofalcon/falcon/client/custom_storage"
fdk "github.com/CrowdStrike/foundry-fn-go"
)
type Incident struct {
ID string `json:"id"`
Title string `json:"title"`
Severity int `json:"severity"`
Status string `json:"status"`
AssignedTo string `json:"assigned_to,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type IncidentStore struct {
client *client.CrowdStrikeAPISpecification
collection string
}
func NewIncidentStore(ctx context.Context) (*IncidentStore, error) {
falconClient, err := falcon.NewClient(fdk.FalconClientOpts())
if err != nil {
return nil, fmt.Errorf("failed to create falcon client: %w", err)
}
return &IncidentStore{client: falconClient, collection: "incidents"}, nil
}
func (s *IncidentStore) Create(ctx context.Context, incident *Incident) error {
incident.ID = generateID()
incident.CreatedAt = time.Now()
incident.UpdatedAt = time.Now()
data, err := json.Marshal(incident)
if err != nil {
return fmt.Errorf("failed to marshal incident: %w", err)
}
params := custom_storage.NewPutObjectParamsWithContext(ctx)
params.SetCollectionName(s.collection)
params.SetObjectKey(incident.ID)
params.SetBody(bytes.NewReader(data))
_, err = s.client.CustomStorage.PutObject(params)
return err
}
func (s *IncidentStore) Get(ctx context.Context, id string) (*Incident, error) {
params := custom_storage.NewGetObjectParamsWithContext(ctx)
params.SetCollectionName(s.collection)
params.SetObjectKey(id)
var buf bytes.Buffer
_, err := s.client.CustomStorage.GetObject(params, &buf)
if err != nil {
return nil, fmt.Errorf("failed to get incident: %w", err)
}
var incident Incident
if err := json.Unmarshal(buf.Bytes(), &incident); err != nil {
return nil, fmt.Errorf("failed to unmarshal incident: %w", err)
}
return &incident, nil
}
func (s *IncidentStore) Delete(ctx context.Context, id string) error {
params := custom_storage.NewDeleteObjectParamsWithContext(ctx)
params.SetCollectionName(s.collection)
params.SetObjectKey(id)
_, err := s.client.CustomStorage.DeleteObject(params)
return err
}
```
SHA-256: 2eba409b628a1080d710ba3746c3c5513f0ea9485b1dc123138a77106aa756ba