Verbinden Sie jedes System, das Sie nutzen.
Das fehlende bauen wir in Stunden.
beetl liest über 100 Systeme ab Werk. Ist Ihres nicht dabei, schreiben wir den Connector mit unserem Open-Source-SDK: eine kurze TypeScript-Datei, geprüft, bevor sie live geht, und jederzeit anpassbar.
Über 100 Verbindungen sind fertig.
Fragen Sie nach der, die fehlt.
Der Katalog, wie er im Produkt aussieht, mit den Systemen, die wir heute lesen. Durchsuchen Sie ihn oder fragen Sie den Assistenten.
Ein ganz neuer Verbindungstyp.
Genau so, wie Sie ihn brauchen.
Ein Verbindungstyp ist eine TypeScript-Datei, der Datenvertrag steht direkt neben dem Code. beetl liest die Datei und baut daraus Einrichtungsformular, Syncs und Datensatz. Scrollen Sie durch.
Das Schema wird zum Datensatz
Fünf Felder, einmal deklariert. Jeder Datensatz wird dagegen geprüft, bevor er gespeichert wird.
const Order = z.object({ id: z.string(), customer: z.string(), total: z.number(), status: z.enum(["open", "shipped", "invoiced"]), updated_at: z.iso.datetime(),});
Inputs werden zum Formular
Zwei Felder und ein Bearer-Token. beetl zeichnet das Formular aus dem Schema, niemand baut UI für einen Connector.
connection: { origin: { type: "input", input: "origin" }, inputs: z.object({ origin: z.url().meta({ title: "ERP address" }), company: z.string().meta({ title: "Company code" }), }), auth: auth.bearer(),
Verify läuft vor dem Speichern
Wiederholungen sind eine Zeile. Verify ruft die API auf, bevor die Verbindung gespeichert wird. Eine falsche Adresse fällt hier auf, nicht beim ersten nächtlichen Sync.
retry: { maxAttempts: 5, statuses: [429, 500, 502, 503] }, async verify(ctx) { await ctx.json(`/api/${ctx.config.company}/orders?limit=1`, Page); },
Merge über id
Ein geänderter Auftrag ersetzt seine alte Version. Ein erneuter Lauf verdoppelt keine Zeile.
syncs: (sync) => ({ orders: sync({ displayName: "Orders", mode: "merge", primaryKey: ["id"], records: Order,
Jede Seite wird mit ihrem Checkpoint gespeichert
Bricht ein Lauf ab, setzt der nächste nach der letzten Seite an, die angekommen ist.
checkpoint: z.object({ since: z.string() }), async *run(ctx) { const { company } = ctx.config.connection; let since = ctx.checkpoint?.since ?? ""; for await (const page of ctx.paginate({ request: { path: `/api/${company}/orders`, query: { since } }, schema: Page, next: ({ data }) => (data.next ? { path: data.next } : undefined), })) { since = page.data.orders.at(-1)?.updated_at ?? since; yield { records: page.data.orders, checkpoint: { since } }; } },
ERP orders Custom
erp-orders.tgz · built and validated
Syncs
Data set erp_orders.orders
| id | string |
| customer | string |
| total | number |
| status | open · shipped · invoiced |
| updated_at | datetime |
Jeden Connector anpassen.
Gleiches SDK, gleiche Prüfung.
Die meisten unserer Connectoren sind mit demselben SDK geschrieben. Jeder ist ein Ausgangspunkt, keine Blackbox. Nur ein Vertriebskanal aus Shopify, ein Feld, das Ihr ERP letztes Jahr bekommen hat, ein anderer Zeitplan: ein paar Zeilen, geprüft wie der Rest.
Orders
Shopify · sync settings
shopify/integration.ts
@@ -43,3 +43,4 @@ const Inputs = z.strictObject({
}),
+salesChannel: z.string().meta({ title: "Sales channel" }).optional(),
pageSize: z.number().int().min(1).max(100).default(50),
@@ -107,2 +108,3 @@ async *run(ctx) {
const filters = config.query ? [`(${config.query})`] : [];
+if (config.salesChannel) filters.push(`sales_channel:${config.salesChannel}`);
if (definition.root === "orders") {
Zwei Zeilen im Shopify-Connector, und der Sync hat eine neue Einstellung.
Schnell geschrieben.
Schwer kaputtzukriegen.
Tempo zählt nur, wenn der Connector auch im sechsten Monat noch läuft. Das SDK übernimmt, was handgeschriebene Integrationen meist falsch machen: Paging, Wiederholungen, Validierung und wo es nach einem Fehler weitergeht.
- Seite 1500 Aufträge · mit Checkpoint gespeichert
- Seite 2500 Aufträge · gespeichert
- Seite 3HTTP 429 · nach 0,5 s und 1 s wiederholt · gespeichert
- Seite 4Worker mitten in der Seite neu gestartet · nichts halb geschrieben
- Nächster LaufSetzt nach Seite 3 an · Seite 4 einmal gespeichert
20
Connectoren an einem Tag, von einem Engineer.
Ein Agent entwirft jeden aus der API-Dokumentation des Anbieters. Ein Engineer prüft ihn, bevor er live geht.
- Jeder Datensatz wird gegen sein Schema geprüft. Was nicht passt, wird abgewiesen, nicht stillschweigend gespeichert.
- Eine Seite und ihr Checkpoint werden zusammen gespeichert. Ein Neustart setzt genau beim letzten Commit an.
- Wiederholungen warten bei Rate-Limits und Serverfehlern länger, innerhalb der Grenzen, die der Connector festlegt.
- Der Connector läuft isoliert. Er bekommt die Zugangsdaten der Quelle, nie die des Ziels.
- Standardmäßig nur lesend. Was die Quelle geschickt hat, bleibt so erhalten, bevor Ihre Mappings laufen.
Keine API?
Dann läuft er in Ihrem Netz.
Manche Systeme sollten nie von außen erreichbar sein: eine ERP-Datenbank im Serverraum, ein Dateiserver, ein Maschinenlog. Ein Site-Connector in Ihrem Netz liest sie und baut einen ausgehenden Tunnel auf. Keine eingehenden Firewall-Regeln, keine offenen Ports.
- DatenbankenNur lesend, über eine eingeschränkte Verbindung
- Dateien und TabellenFreigaben, Uploads und Object Storage
- WebhooksTypisiert und beim Eingang gegen das Schema geprüft
- Lokale SystemeÜber den Site-Connector
Ihr Netz
ERP-DatenbankSite-ConnectorOpen Source.
Apache 2.0.
Das SDK ist öffentlich. Ihre Engineers sehen genau, was läuft, testen einen Connector auf dem Laptop gegen die echte API und schreiben eigene. Laden Sie das Paket in beetl hoch, oder schicken Sie es uns zur Prüfung.
Das SDK auf GitHub ↗# SDK hinzufügen$ npm install --save-dev @beetlio/connect# Verbindung einrichten und einen Sync auf dem Laptop laufen lassen$ npx beetl-connect configure . orders$ npx beetl-connect sync . orders --output orders.ndjson# für beetl packen$ npx beetl-connect pack .