Zum Hauptinhalt springen
Version: 0.3.0

gRPC

Der Server ist mit Connect-RPC gebaut, daher beantworten dieselben Handler gRPC (HTTP/2), gRPC-Web und das Connect-Protokoll. Er lauscht mit h2c, sodass gRPC auch ohne vorgeschaltetes TLS funktioniert; in Produktion terminiert ein Reverse-Proxy TLS.

Einen Client generieren​

Der Vertrag liegt in proto/openbeehive/v1 und wird mit buf gebaut. Die buf.gen.yaml des Repos generiert Go (protocolbuffers/go + connectrpc/go) nach server/internal/gen und TypeScript (bufbuild/es v2) nach app/src/lib/proto. Beide Ausgabeverzeichnisse sind gitignored; führe nach dem Klonen make proto aus. Für eine andere Sprache kopierst du das Verzeichnis proto/ und richtest deine eigene buf.gen.yaml auf die Plugins aus, die du brauchst.

Go​

import (
"connectrpc.com/connect"
obv1 "github.com/openbeehive-org/openbeehive-app/server/internal/gen/openbeehive/v1"
"github.com/openbeehive-org/openbeehive-app/server/internal/gen/openbeehive/v1/openbeehivev1connect"
)

client := openbeehivev1connect.NewApiaryServiceClient(http.DefaultClient, "https://bees.example.com")
req := connect.NewRequest(&obv1.ListApiariesRequest{})
req.Header().Set("Authorization", "Bearer "+token)
res, err := client.ListApiaries(ctx, req)

Jeder der zehn Dienste hat seinen eigenen Client-Konstruktor (NewApiaryServiceClient, NewHiveServiceClient, NewQueenServiceClient, NewInspectionServiceClient, NewTaskServiceClient, NewTreatmentServiceClient, NewHarvestServiceClient, NewEventServiceClient, NewStatsServiceClient, NewSyncServiceClient). Eine Stockwaage zum Beispiel sendet über den InspectionService:

insp := openbeehivev1connect.NewInspectionServiceClient(http.DefaultClient, "https://bees.example.com")
req := connect.NewRequest(&obv1.CreateInspectionRequest{HiveId: hiveID, WeightKg: 42.5, TempHive: 34.2})
req.Header().Set("Authorization", "Bearer "+token)
res, err := insp.CreateInspection(ctx, req)

Das generierte Paket ist internal im Server-Modul, ein eigenständiges Go-Programm muss sich also seine eigene Kopie aus den .proto-Dateien generieren.

TypeScript​

Der Client der App selbst liegt in app/src/lib/client.ts:

import { createClient } from '@connectrpc/connect';
import { createConnectTransport } from '@connectrpc/connect-web';
import { SyncService } from './proto/openbeehive/v1/sync_pb';

const transport = createConnectTransport({ baseUrl: origin, interceptors: [authInterceptor] });
export const syncClient = createClient(SyncService, transport);

authInterceptor setzt Authorization: Bearer <token> aus der gespeicherten Sitzung.

Aus der Shell​

buf curl spricht alle drei Protokolle und nutzt dafür das Schema aus dem Repo:

cd openbeehive-app
buf curl --schema . \
--header "Authorization: Bearer $TOKEN" \
--data '{"apiaryId":"2b1f6c0e-..."}' \
https://bees.example.com/openbeehive.v1.HiveService/ListHives

Mit --protocol grpc erzwingst du gRPC statt Connect.

Authentifizierung​

Sende einen API-Schlüssel (obhk_..., erstellt unter Einstellungen → API-Schlüssel) oder ein Sitzungstoken als Header Authorization: Bearer <token> (gRPC-Metadaten); token in den Snippets oben ist eines von beiden. Für Sitzungstokens wird auch das Cookie obh_session akzeptiert. Derselbe Interceptor prüft beide Arten und deckt unäre Aufrufe und den Subscribe-Stream gleichermaßen ab. Eine Instanz ohne konfigurierte Anmeldemethode braucht keinen Header. Siehe den Überblick.

Subscribe​

rpc Subscribe(SubscribeRequest) returns (stream SubscribeEvent);
message SubscribeRequest { string cursor = 1; }
message SubscribeEvent { string server_cursor = 1; }

Der Server fragt alle zwei Sekunden seinen globalen Änderungszähler ab und sendet ein SubscribeEvent, sobald der Zähler über den von dir gesendeten Cursor hinausgegangen ist (und über den zuletzt gesendeten Wert). Das Ereignis trägt keine Daten; rufe Pull mit deinem gespeicherten Cursor auf, wenn du eines empfängst. Auch Zeilen außerhalb deiner Scopes erhöhen den Zähler, ein Pull nach einem Ereignis kann also leer zurückkommen.

Die App nutzt Subscribe nicht; sie pusht und pullt alle 15 Sekunden, nach jedem lokalen Schreibvorgang und beim online-Ereignis des Browsers.