Připojení externí aplikace k Lakebase pomocí rozhraní API

Tento průvodce ukazuje, jak připojit externí aplikace k automatickému škálování Lakebase pomocí přímých volání rozhraní REST API. Tento přístup použijte, když není sada Databricks SDK dostupná pro váš jazyk (Node.js, Ruby, PHP, Elixir, Rust atd.).

Pokud váš jazyk podporuje sadu SDK (Python, Java nebo Go), pro jednodušší správu tokenů použijte připojení externí aplikace k Lakebase pomocí sady SDK .

Provedete dvě volání rozhraní API pro získání přihlašovacích údajů databáze s rotací tokenů OAuth. Příklady jsou k dispozici pro curl a Node.js.

Poznámka:

Dvoustupňové ověřování: Tento přístup vyžaduje dvě volání API pro každý přihlašovací údaj databáze: (1) výměna tajného klíče instančního objektu za token OAuth pracovního prostoru, (2) výměna tokenu OAuth za přihlašovací údaj databáze. Platnost obou tokenů vyprší po 60 minutách. Sada SDK zpracovává krok 1 automaticky.

Předpoklady

Potřebujete stejné nastavení jako při použití SDK: služební principál, role PostgreSQL a podrobnosti o připojení.

Předpoklad Klíčový detail Více informací
Služba principal Tajný kód OAuth s maximální životností 730 dnů ; povolte přístup k pracovnímu prostoru. Poznamenejte si ID klienta (UUID) pro roli Postgres a env vars. Vytvoření služebního principála
Postgres Role Vytvořte roli OAuth v Editoru SQL Lakebase: databricks_create_role('{client-id}', 'SERVICE_PRINCIPAL') a udělte CONNECT, USAGE, SELECT/INSERT/UPDATE/DELETE. Použijte ID klienta z kroku 1. Vytvoření role Postgres
Podrobnosti o připojení Z konzoly Lakebase Connect: název koncového bodu (projects/.../branches/.../endpoints/...), hostitel, databáze (obvykle databricks_postgres). Získání podrobností o připojení

Jak to funguje

Ruční přístup rozhraní API vyžaduje dvě výměny tokenů:

Tok ruční výměny tokenů rozhraní API

Životnost tokenů:

  • Tajný klíč Service Principal: Až 730 dnů (nastaveno během vytváření)
  • Token OAuth pracovního prostoru: 60 minut (krok 1)
  • Přihlašovací údaje databáze: 60 minut (krok 2)

Rozsah tokenů: Přihlašovací údaje databáze mají rozsah pracovního prostoru. Ačkoli je parametr endpoint povinný, vrácený token má přístup k jakékoli databázi nebo projektu v pracovním prostoru, ke kterému má hlavní služba oprávnění.

Nastavení proměnných prostředí

Před spuštěním aplikace nastavte tyto proměnné prostředí:

# Databricks workspace authentication
export DATABRICKS_HOST="https://your-workspace.databricks.com"
export DATABRICKS_CLIENT_ID="<service-principal-client-id>"
export DATABRICKS_CLIENT_SECRET="<your-oauth-secret>"

# Lakebase connection details (from prerequisites)
export ENDPOINT_NAME="projects/<project-id>/branches/<branch-id>/endpoints/<endpoint-id>"
export PGHOST="<endpoint-id>.database.<region>.cloud.databricks.com"
export PGDATABASE="databricks_postgres"
export PGUSER="<service-principal-client-id>"   # Same UUID as client ID
export PGPORT="5432"

Přidání kódu připojení

kroucení

Tento příklad ukazuje nezpracovaná volání rozhraní API. Pro produkční aplikace implementujte logiku ukládání tokenů do mezipaměti a aktualizace.

# Step 1: Get workspace OAuth token
OAUTH_TOKEN=$(curl -s -X POST "${DATABRICKS_HOST}/oidc/v1/token" \
  -u "${DATABRICKS_CLIENT_ID}:${DATABRICKS_CLIENT_SECRET}" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&scope=all-apis" \
  | jq -r '.access_token')

echo "Got workspace OAuth token (60-min lifetime)"

# Step 2: Get database credential
PG_TOKEN=$(curl -s -X POST "${DATABRICKS_HOST}/api/2.0/postgres/credentials" \
  -H "Authorization: Bearer ${OAUTH_TOKEN}" \
  -H "Content-Type: application/json" \
  -d "{\"endpoint\": \"${ENDPOINT_NAME}\"}" \
  | jq -r '.token')

echo "Got database credential (60-min lifetime)"

# Step 3: Connect to Postgres
PGPASSWORD="${PG_TOKEN}" psql \
  -h "${PGHOST}" \
  -p "${PGPORT}" \
  -U "${PGUSER}" \
  -d "${PGDATABASE}" \
  -c "SELECT current_user, current_database()"

Node.js

V tomto příkladu se používá node-postgres s asynchronní funkcí hesla, která zpracovává načítání a ukládání tokenů do mezipaměti.

import pg from 'pg';

// Step 1: Fetch workspace OAuth token
async function getWorkspaceToken(host, clientId, clientSecret) {
  const auth = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
  const response = await fetch(`${host}/oidc/v1/token`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Authorization: `Basic ${auth}`,
    },
    body: 'grant_type=client_credentials&scope=all-apis',
  });

  if (!response.ok) {
    throw new Error(`OAuth failed: ${response.status}`);
  }

  const data = await response.json();
  return {
    token: data.access_token,
    expires: Date.now() + data.expires_in * 1000,
  };
}

// Step 2: Fetch database credential
async function getPostgresCredential(host, workspaceToken, endpoint) {
  const response = await fetch(`${host}/api/2.0/postgres/credentials`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${workspaceToken}`,
    },
    body: JSON.stringify({ endpoint }),
  });

  if (!response.ok) {
    throw new Error(`Database credential failed: ${response.status}`);
  }

  const data = await response.json();
  return {
    token: data.token,
    expires: new Date(data.expire_time).getTime(),
  };
}

// Simple caching wrapper (production: use more sophisticated caching)
function cached(fetchFn) {
  let cache = null;
  return async (...args) => {
    const now = Date.now();
    if (!cache || now >= cache.expires - 5 * 60 * 1000) {
      // Refresh 5 min early
      const result = await fetchFn(...args);
      cache = result;
    }
    return cache.token;
  };
}

// Create connection pool with async password function
function createPool() {
  const host = process.env.DATABRICKS_HOST;
  const clientId = process.env.DATABRICKS_CLIENT_ID;
  const clientSecret = process.env.DATABRICKS_CLIENT_SECRET;
  const endpoint = process.env.ENDPOINT_NAME;

  const cachedWorkspaceToken = cached(() => getWorkspaceToken(host, clientId, clientSecret));
  const cachedPostgresToken = cached(async () => {
    const workspaceToken = await cachedWorkspaceToken();
    return getPostgresCredential(host, workspaceToken, endpoint);
  });

  return new pg.Pool({
    host: process.env.PGHOST,
    port: process.env.PGPORT,
    database: process.env.PGDATABASE,
    user: process.env.PGUSER,
    password: cachedPostgresToken, // Async function: () => Promise<string>
    ssl: { rejectUnauthorized: true },
    min: 1,
    max: 10,
    idleTimeoutMillis: 900000, // Example: 15 minutes
    connectionTimeoutMillis: 60000, // Example: 60 seconds
  });
}

// Use the pool
const pool = createPool();
const result = await pool.query('SELECT current_user, current_database()');
console.log('Connected as:', result.rows[0].current_user);

Závislosti:pg (node-postgres)

Poznámka: Node-postgres (pg) přijímá asynchronní funkci jako heslo. Funkce se volá při každém vytvoření nového připojení a zajišťuje nové tokeny.

Spuštění a ověření připojení

kroucení

Spusťte skript Bash s načtenými proměnnými prostředí:

export $(cat .env | xargs)
bash connect.sh

Očekávaný výstup:

Got workspace OAuth token (60-min lifetime)
Got database credential (60-min lifetime)
     current_user      | current_database
-----------------------+------------------
 c00f575e-d706-4f6b... | databricks_postgres

Pokud current_user odpovídá ID klienta hlavního objektu služby, funguje OAuth správně.

Node.js

Nainstalujte závislosti:

npm install pg

Spustit:

node app.js

Očekávaný výstup:

Connected as: c00f575e-d706-4f6b-b62c-e7a14850571b

Poznámka: První připojení po nečinnosti může trvat déle, protože automatické škálování LakeBase spouští výpočetní prostředky od nuly.

Řešení problémů

Error Oprava
"invalid_client" nebo "Chybějící ověřování klientů" Zkontrolujte DATABRICKS_CLIENT_ID a DATABRICKS_CLIENT_SECRET jsou správná. Použití základního ověřování (kódování base64)
Rozhraní API je pro uživatele bez oprávnění přístupu k pracovnímu prostoru deaktivováno. Pro služební účel povolte přístup k pracovnímu prostoru (požadavky).
"INVALID_PARAMETER_VALUE" / "Pole 'koncový bod' je povinné" Ujistěte se, že endpoint parametr je součástí kroku 2 POST s formátem projects/<id>/branches/<id>/endpoints/<id>.
Role neexistuje nebo se ověření nezdaří Vytvoření role OAuth prostřednictvím SQL (požadavky)
"Připojení odmítnuto" nebo vypršení časového limitu První připojení po škálování na nulu může trvat déle. Implementujte logiku opakování.
Platnost tokenu vypršela / Ověření hesla se nezdařilo. Platnost tokenů pracovního prostoru i databáze vyprší po 60 minutách. Implementujte ukládání do mezipaměti s kontrolami vypršení platnosti.