SP SPACEPLACE
EXAMPLE #07 PHP Bash

Reusable client

A reusable PHP class and Bash function set for any script.

07-reusable-client.php
#!/usr/bin/env php
<?php

/**
 * Example: Reusable client class for the Space Place API
 *
 * Wraps authentication and event creation into a simple class that can be
 * dropped into any PHP project.
 *
 * Usage:
 *   php 07-reusable-client.php
 *
 *   // Or require it from another script:
 *   require_once __DIR__ . '/07-reusable-client.php';
 *   $client = new SpacePlaceClient('http://...', 'ds-uuid', 'token-value');
 *   $client->sendEvent(number: 1, key: 'metric', value: '99');
 */

class SpacePlaceClient
{
    public function __construct(
        private string $baseUrl,
        private string $dataStreamId,
        private string $tokenValue,
        private int    $timeout = 10,
    ) {}

    /**
     * Send a single event.
     *
     * @return array{success: bool, event_id: ?string, timestamp: ?string, error: ?string}
     */
    public function sendEvent(
        int     $number = 0,
        string  $source = '',
        string  $key = '',
        string  $value = '',
        ?string $timestamp = null,
    ): array {
        $payload = compact('number', 'source', 'key', 'value');
        if ($timestamp !== null) {
            $payload['timestamp'] = $timestamp;
        }

        return $this->post('/api/events', $payload);
    }

    /**
     * Send multiple events. Returns an array of results, one per event.
     *
     * @param  array<array{number?: int, source?: string, key?: string, value?: string, timestamp?: string}> $events
     * @return array<array{success: bool, event_id: ?string, timestamp: ?string, error: ?string}>
     */
    public function sendBatch(array $events): array
    {
        $results = [];
        foreach ($events as $event) {
            $results[] = $this->sendEvent(
                number:    $event['number'] ?? 0,
                source:    $event['source'] ?? '',
                key:       $event['key'] ?? '',
                value:     $event['value'] ?? '',
                timestamp: $event['timestamp'] ?? null,
            );
        }
        return $results;
    }

    private function post(string $path, array $payload): array
    {
        $ch = curl_init("{$this->baseUrl}{$path}");
        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => $this->timeout,
            CURLOPT_HTTPHEADER     => [
                'Content-Type: application/json',
                'Accept: application/json',
                "X-DataStream-ID: {$this->dataStreamId}",
                "X-Token: {$this->tokenValue}",
            ],
            CURLOPT_POSTFIELDS => json_encode($payload),
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error    = curl_error($ch);
        curl_close($ch);

        if ($error) {
            return ['success' => false, 'event_id' => null, 'timestamp' => null, 'error' => "cURL: {$error}"];
        }

        $body = json_decode($response, true) ?? [];

        if ($httpCode === 201) {
            return [
                'success'   => true,
                'event_id'  => $body['event_id'] ?? null,
                'timestamp' => $body['timestamp'] ?? null,
                'error'     => null,
            ];
        }

        return [
            'success'   => false,
            'event_id'  => null,
            'timestamp' => null,
            'error'     => "HTTP {$httpCode}: " . ($body['error'] ?? $body['message'] ?? $response),
        ];
    }
}

// ── Demo usage ───────────────────────────────────────────────────────────────

// Only run the demo when this file is executed directly
if (realpath($argv[0] ?? '') === realpath(__FILE__)) {

    $client = new SpacePlaceClient(
        baseUrl:      'https://www.spaceplace.app',
        dataStreamId: 'YOUR-DATASTREAM-UUID-HERE',
        tokenValue:   'YOUR-TOKEN-VALUE-HERE',
    );

    // Single event
    echo "Sending single event...\n";
    $result = $client->sendEvent(number: 1, source: 'client-demo', key: 'ping', value: 'pong');
    if ($result['success']) {
        echo "  Created: {$result['event_id']}\n";
    } else {
        echo "  Error: {$result['error']}\n";
    }

    // Batch of events
    echo "\nSending batch of 3 events...\n";
    $results = $client->sendBatch([
        ['number' => 1, 'source' => 'client-demo', 'key' => 'cpu',    'value' => '45.2'],
        ['number' => 2, 'source' => 'client-demo', 'key' => 'memory', 'value' => '72.8'],
        ['number' => 3, 'source' => 'client-demo', 'key' => 'disk',   'value' => '31.0'],
    ]);

    foreach ($results as $i => $r) {
        $status = $r['success'] ? "OK ({$r['event_id']})" : "FAIL ({$r['error']})";
        echo "  Event " . ($i + 1) . ": {$status}\n";
    }
}
07-reusable-functions.sh
#!/usr/bin/env bash
#
# Example: Reusable functions for the Space Place API
#
# Source this file from other scripts, or run it directly for a demo.
#
# Usage:
#   bash 07-reusable-functions.sh
#
#   # Or source from another script:
#   source ./07-reusable-functions.sh
#   sp_configure "https://www.spaceplace.app" "ds-uuid" "token-value"
#   sp_send_event 1 "my-source" "metric" "99"

SP_BASE_URL=""
SP_DATASTREAM_ID=""
SP_TOKEN_VALUE=""

sp_configure() {
  SP_BASE_URL="$1"
  SP_DATASTREAM_ID="$2"
  SP_TOKEN_VALUE="$3"
}

# Send a single event. Returns 0 on success, 1 on failure.
# Usage: sp_send_event <number> <source> <key> <value> [timestamp]
sp_send_event() {
  local number="${1:-0}"
  local source="${2:-}"
  local key="${3:-}"
  local value="${4:-}"
  local timestamp="${5:-}"

  local ts_field=""
  if [ -n "$timestamp" ]; then
    ts_field="\"timestamp\": \"${timestamp}\","
  fi

  local response
  response=$(curl -s -w "\n%{http_code}" --max-time 10 \
    -X POST "${SP_BASE_URL}/api/events" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-DataStream-ID: ${SP_DATASTREAM_ID}" \
    -H "X-Token: ${SP_TOKEN_VALUE}" \
    -d "{
      ${ts_field}
      \"number\": ${number},
      \"source\": \"${source}\",
      \"key\": \"${key}\",
      \"value\": \"${value}\"
    }")

  local http_code body
  http_code=$(echo "$response" | tail -n1)
  body=$(echo "$response" | sed '$d')

  if [ "$http_code" = "201" ]; then
    SP_LAST_EVENT_ID=$(echo "$body" | jq -r '.event_id')
    SP_LAST_TIMESTAMP=$(echo "$body" | jq -r '.timestamp')
    return 0
  else
    SP_LAST_ERROR="HTTP ${http_code}: $(echo "$body" | jq -r '.error // .message // "unknown"')"
    return 1
  fi
}

# List events. Extra curl args can be appended.
# Usage: sp_list_events [query_string]
# Example: sp_list_events "key=temperature&per_page=10"
sp_list_events() {
  local query="${1:-}"
  local url="${SP_BASE_URL}/api/events"
  [ -n "$query" ] && url="${url}?${query}"

  curl -s \
    -H "Accept: application/json" \
    -H "X-DataStream-ID: ${SP_DATASTREAM_ID}" \
    -H "X-Token: ${SP_TOKEN_VALUE}" \
    "$url"
}

# Get events since a datetime.
# Usage: sp_events_since <datetime> [extra_query_params]
sp_events_since() {
  local since="$1"
  local extra="${2:-}"
  local query="since=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${since}'))")"
  [ -n "$extra" ] && query="${query}&${extra}"

  curl -s \
    -H "Accept: application/json" \
    -H "X-DataStream-ID: ${SP_DATASTREAM_ID}" \
    -H "X-Token: ${SP_TOKEN_VALUE}" \
    "${SP_BASE_URL}/api/events/since?${query}"
}

# Get a single event.
# Usage: sp_get_event <event-uuid>
sp_get_event() {
  curl -s \
    -H "Accept: application/json" \
    -H "X-DataStream-ID: ${SP_DATASTREAM_ID}" \
    -H "X-Token: ${SP_TOKEN_VALUE}" \
    "${SP_BASE_URL}/api/events/$1"
}

# Update an event.
# Usage: sp_update_event <event-uuid> <json-payload>
sp_update_event() {
  curl -s \
    -X PUT \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "X-DataStream-ID: ${SP_DATASTREAM_ID}" \
    -H "X-Token: ${SP_TOKEN_VALUE}" \
    -d "$2" \
    "${SP_BASE_URL}/api/events/$1"
}

# Delete an event.
# Usage: sp_delete_event <event-uuid>
sp_delete_event() {
  curl -s \
    -X DELETE \
    -H "Accept: application/json" \
    -H "X-DataStream-ID: ${SP_DATASTREAM_ID}" \
    -H "X-Token: ${SP_TOKEN_VALUE}" \
    "${SP_BASE_URL}/api/events/$1"
}

# ── Demo (only runs when executed directly, not when sourced) ─────────────────

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
  sp_configure \
    "https://www.spaceplace.app" \
    "YOUR-DATASTREAM-UUID-HERE" \
    "YOUR-TOKEN-VALUE-HERE"

  echo "--- Sending single event ---"
  if sp_send_event 1 "func-demo" "ping" "pong"; then
    echo "  Created: ${SP_LAST_EVENT_ID}"
  else
    echo "  Error: ${SP_LAST_ERROR}"
  fi

  echo ""
  echo "--- Sending batch of 3 events ---"
  for metric in "cpu:45.2" "memory:72.8" "disk:31.0"; do
    key="${metric%%:*}"
    val="${metric##*:}"
    if sp_send_event 0 "func-demo" "$key" "$val"; then
      echo "  ${key}: OK (${SP_LAST_EVENT_ID})"
    else
      echo "  ${key}: FAIL (${SP_LAST_ERROR})"
    fi
  done
fi
← All examples