SQL Connect ile Admin SDK'yı kullanma

Firebase Admin SDK, ayrıcalıklı ortamlardan Firebase ile etkileşim kurmanıza olanak tanıyan bir sunucu kitaplıkları kümesidir. Bu kitaplıklar, toplu veri yönetimi için Firebase SQL Connect hizmetinde sorgu ve mutasyon gerçekleştirme gibi işlemlerin yanı sıra üst düzey ayrıcalıklar ve kimliğe bürünme kimlik bilgileriyle diğer işlemleri yapmanıza olanak tanır.

Admin SDK, hem okuma/yazma hem de salt okunur modlarda işlemleri çağırmak için bir API sağlar. Salt okunur işlemlerle, veritabanlarınızdaki verileri değiştiremeyen yönetim işlevlerini uygulamanın rahatlığını yaşarsınız.

Yönetici SDK'sını Kurulumu

Sunucunuzda Firebase SQL Connect kullanmaya başlamak için öncelikle Node.js için Admin SDK'ı yükleyip ayarlamanız gerekir.

Admin SDK'yı komut dosyalarınızda başlatma

SDK'yı ilk kullanıma hazırlamak için SQL Connect uzantılarını içe aktarın ve proje hizmeti kimliğinizi ve konumunuzu tanımlayın.


import { initializeApp } from 'firebase-admin/app';
import { getDataConnect } from 'firebase-admin/data-connect';

// If you'd like to use OAuth2 flows and other credentials to log in,
// visit https://firebase.google.com/docs/admin/setup#initialize-sdk
// for alternative ways to initialize the SDK.

const app = initializeApp();

const dataConnect = getDataConnect({
    serviceId: 'serviceId',
    location: 'us-west2'
});

Admin SDK ile kullanılacak sorgular ve mutasyonlar tasarlama

Aşağıdaki hususlar göz önünde bulundurulduğunda Admin SDK, SQL Connect işlemlerini çalıştırmak için yararlıdır.

SDK'yı ve @auth(level: NO_ACCESS) işlem yönergesini anlama

Admin SDK ayrıcalıklarla çalıştığından, NO_ACCESS düzeyi de dahil olmak üzere @auth yönergeleri kullanılarak ayarlanan erişim düzeylerinden bağımsız olarak sorgularınızın ve mutasyonlarınızın herhangi birini yürütebilir.

İstemci işlemlerinizin yanı sıra yönetim sorgularınızı ve mutasyonlarınızı yönetim komut dosyalarına aktarmak için .gql kaynak dosyalarında düzenliyorsanız Firebase, yetkilendirme erişim düzeyi olmayan yönetim işlemlerini işaretlemenizi veya daha açık bir şekilde NO_ACCESS olarak ayarlamanızı önerir. Her iki durumda da bu işlemlerin istemcilerden veya ayrıcalıklı olmayan diğer bağlamlarda yürütülmesi önlenir.

SDK'yı SQL Connect emülatörüyle kullanma

Prototip ve test ortamlarında, yerel verilerde veri doldurma ve diğer işlemleri yapmak faydalı olabilir. Admin SDK, yerel akışlar için kimlik doğrulama ve yetkilendirmeyi yoksayabildiğinden iş akışlarınızı basitleştirmenize olanak tanır. (Ayrıca, kullanıcı kimliğine bürünme ile işlemlerinizin kimlik doğrulama ve yetkilendirme yapılandırmasına uymayı açıkça etkinleştirebilirsiniz.)

Firebase Admin SDK'ları, SQL Connect ortam değişkeni ayarlandığında otomatik olarak DATA_CONNECT_EMULATOR_HOST emülatörüne bağlanır:

export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"

Daha fazla bilgi için aşağıdaki sayfaları inceleyin:

Yönetici işlemlerini çalıştırma

Admin SDK, kritik verilerinizdeki ayrıcalıklı işlemler için sağlanır.

Yönetici SDK'sı üç API grubu sunar:

  • İstemci SDK'larını oluşturduğunuz şekilde gql tanımlarınızdan oluşturulan tür güvenli SDK'lar olan oluşturulmuş yönetici SDK'ları.
  • Sorguları ve mutasyonları kodunuzun uyguladığı, bunları okuma-yazma executeGraphql yöntemine veya salt okunur executeGraphqlRead yöntemine ilettiği, rastgele GraphQL işlemlerini çalıştırmak için kullanılan genel bir arayüz.
  • Toplu veri işlemleri için özel bir arayüz. Bu arayüz, genel executeGraphql yöntemleri yerine mutasyon işlemleri için özel yöntemler (insert, insertMany, upsert ve upsertMany) sunar.

Oluşturulan SDK'larla verileri yönetme

Yönetici SDK'larını, istemci SDK'larını oluşturduğunuz şekilde gql tanımlarınızdan oluşturursunuz.

Oluşturulan yönetici SDK'sı, gql tanımlarınıza karşılık gelen arayüzler ve işlevler içerir. Bunları, veritabanınızda işlemler gerçekleştirmek için kullanabilirsiniz. Örneğin, şarkı veritabanı için bir SDK oluşturduğunuzu ve getSongs sorgusunu kullandığınızı varsayalım:

import { initializeApp } from "firebase-admin/app";
import { getSongs } from "@dataconnect/admin-generated";

const adminApp = initializeApp();

const songs = await getSongs(
  { limit: 4 },
  { impersonate: { unauthenticated: true } }
);

Alternatif olarak, bağlayıcı yapılandırması belirtmek için:

import { initializeApp } from "firebase-admin/app";
import { getDataConnect } from "firebase-admin/data-connect";
import {
  connectorConfig,
  getSongs,
} from "@dataconnect/admin-generated";

const adminApp = initializeApp();
const adminDc = getDataConnect(connectorConfig);

const songs = await getSongs(
  adminDc,
  { limit: 4 },
  { impersonate: { unauthenticated: true } }
);

Kimliği doğrulanmamış bir kullanıcının kimliğine bürünme

Admin SDK'ları güvenilir ortamlarda çalıştırılmak üzere tasarlanmıştır ve bu nedenle veritabanlarınıza sınırsız erişime sahiptir.

Yönetici SDK'sı ile herkese açık işlemler çalıştırırken işlemi tam yönetici ayrıcalıklarıyla çalıştırmaktan kaçınmalısınız (en az ayrıcalık ilkesine uymak). Bunun yerine, işlemi kimliğine bürünülmüş bir kullanıcı (sonraki bölüme bakın) veya kimliği doğrulanmamış bir kullanıcı olarak çalıştırmanız gerekir. Kimliği doğrulanmamış kullanıcılar yalnızca PUBLIC olarak işaretlenen işlemleri çalıştırabilir.

Yukarıdaki örnekte, getSongs sorgusu kimliği doğrulanmamış bir kullanıcı olarak yürütülür.

Bir kullanıcının kimliğine bürünme

Ayrıca, Firebase Authentication seçeneğinde impersonate jetonunun bir kısmını veya tamamını ileterek belirli kullanıcılar adına işlemler de gerçekleştirebilirsiniz. En azından, alt talebinde kullanıcının kullanıcı kimliğini belirtmeniz gerekir. (Bu, SQL Connect GraphQL işlemlerinde referans verebileceğiniz auth.uid sunucu değeriyle aynı değerdir.)

Bir kullanıcının kimliğine büründüğünüzde, sağladığınız kullanıcı verileri GraphQL tanımınızda belirtilen kimlik doğrulama kontrollerini geçerse işlem başarılı olur.

Oluşturulan SDK'yı herkese açık bir uç noktadan çağırıyorsanız uç noktanın kimlik doğrulama gerektirmesi ve kimlik doğrulama jetonunun bütünlüğünü, kullanıcı kimliğine bürünmek için kullanmadan önce doğrulamanız çok önemlidir.

Arama yapılabilir Cloud Functions kullanılırken kimlik doğrulama jetonu otomatik olarak doğrulanır ve aşağıdaki örnekte olduğu gibi kullanılabilir:

import { HttpsError, onCall } from "firebase-functions/https";

export const callableExample = onCall(async (req) => {
    const authClaims = req.auth?.token;
    if (!authClaims) {
        throw new HttpsError("unauthenticated", "Unauthorized");
    }

    const favoriteSongs = await getMyFavoriteSongs(
        undefined,
        { impersonate: { authClaims } }
    );

    // ...
});

Aksi takdirde, kimlik doğrulama jetonunu doğrulamak ve kodunu çözmek için Admin SDK'nın verifyIdToken yöntemini kullanın. Örneğin, uç noktanızın düz bir HTTP işlevi olarak uygulandığını ve standart olduğu gibi Firebase Authentication üst bilgisini kullanarak authorization jetonunu uç noktanıza ilettiğinizi varsayalım:

import { getAuth } from "firebase-admin/auth";
import { onRequest } from "firebase-functions/https";

const auth = getAuth();

export const httpExample = onRequest(async (req, res) => {
    const token = req.header("authorization")?.replace(/^bearer\s+/i, "");
    if (!token) {
        res.sendStatus(401);
        return;
    }
    let authClaims;
    try {
        authClaims = await auth.verifyIdToken(token);
    } catch {
        res.sendStatus(401);
        return;
    }

    const favoriteSongs = await getMyFavoriteSongs(
        undefined,
        { impersonate: { authClaims } }
    );

    // ...
});

Yalnızca güvenli ve herkese açık olmayan bir ortamda veri taşıma gibi gerçek idari görevleri gerçekleştirirken doğrulanabilir bir kaynaktan gelmeyen bir kullanıcı kimliği belirtmeniz gerekir:

// Never do this if end users can initiate execution of the code!
const favoriteSongs = await getMyFavoriteSongs(
  undefined,
  { impersonate: { authClaims } }
);

Sınırsız erişimle çalıştırma

Yönetici düzeyinde izinler gerektiren bir işlem yapıyorsanız çağrıdan kimliğe bürünme parametresini çıkarın:

await upsertSong(adminDc, {
  title: songTitle_one,
  instrumentsUsed: [Instrument.VOCAL],
});

Bu şekilde çağrılan bir işlem, veritabanına tam erişime sahiptir. Yalnızca yönetim amaçlarıyla kullanılmak üzere tasarlanmış sorgularınız veya mutasyonlarınız varsa bunları @auth(level: NO_ACCESS) yönergesiyle tanımlamanız gerekir. Bu sayede, yalnızca yönetici düzeyindeki arayanların bu işlemleri gerçekleştirebilmesi sağlanır.

Verileri executeGraphql yöntemleriyle yönetme

gql Mutasyon veya sorgu tanımlamadığınız tek seferlik işlemleri yürütmeniz gerekiyorsa executeGraphql yöntemini ya da salt okunur executeGraphqlRead yöntemini kullanabilirsiniz.

executeGraphql kullanarak özel iç içe yerleştirilmiş ilişkisel işlemler (bire-çok) gerçekleştirme

Yönetici SDK'sından ayrıcalıklı bir ortamda işlemler çağırırken standart düz (iç içe olmayan) eklemeler (ör. ayrı ayrı Film veya Oyuncu kayıtları ekleme) için değişkenlerinizde @allow yönergesini belirtmeniz gerekmez.

Ancak iç içe yerleştirilmiş ilişkisel eklemeler (ör. bir filmi ilk yorumlarıyla birlikte ekleme) için, derlenmiş değişken şemasındaki iç içe yerleştirilmiş ilişkisel alanlara statik olarak izin vermek üzere değişken tanımınızda @allow yönergesini yine de bildirmeniz gerekir.

// Custom GraphQL mutation with nested relational insert
const customMutation = `
  mutation CustomBatchInsert(
    $data: [Movie_Data!]!
    @allow(fields: "title genre reviews_on_movie { rating reviewText }")
  ) {
    movie_insertMany(data: $data)
  }
`;
const variables = {
  data: [
    {
      title: "Interstellar",
      genre: "Sci-Fi",
      reviews_on_movie: [
        {
          rating: 5,
          reviewText: "Visually stunning and emotionally powerful.",
          user: { id: "user-789" }
        }
      ]
    }
  ]
};
const response = await dataConnect.executeGraphql(customMutation, { variables });

Kimliği doğrulanmamış bir kullanıcının kimliğine bürünme

Yönetici SDK'sı ile herkese açık işlemler çalıştırırken işlemi tam yönetici ayrıcalıklarıyla çalıştırmaktan kaçınmalısınız (en az ayrıcalık ilkesine uymak). Bunun yerine, işlemi kimliğe bürünmüş bir kullanıcı olarak (sonraki bölüme bakın) veya kimliği doğrulanmamış bir kullanıcı olarak çalıştırmanız gerekir. Kimliği doğrulanmamış kullanıcılar yalnızca PUBLIC olarak işaretlenen işlemleri çalıştırabilir.

// Query to get posts, with authentication level PUBLIC
const queryGetPostsImpersonation = `
    query getPosts @auth(level: PUBLIC) {
        posts {
          description
        }
    }`;

// Attempt to access data as an unauthenticated user
const optionsUnauthenticated: GraphqlOptions<undefined> = {
    impersonate: {
        unauthenticated: true
    }
};

// executeGraphql with impersonated unauthenticated user scope
const gqlResponse = await dataConnect.executeGraphql<UserData, undefined>(queryGetPostsImpersonation, optionsUnauthenticated);

Bir kullanıcının kimliğine bürünme

Ayrıca, komut dosyalarınızın belirli bir kullanıcı adına sınırlı kimlik bilgilerine göre kullanıcı verilerini değiştirmesini istediğiniz kullanım alanları da vardır. Bu yaklaşım, en az ayrıcalık ilkesine uygundur.

Bu arayüzü kullanmak için Authentication jeton biçimini izleyen özelleştirilmiş bir JWT kimlik doğrulama jetonundan bilgi toplayın. Ayrıca özel jetonlar kılavuzuna da bakın.

// Get the current user's data
const queryGetUserImpersonation = `
    query getUser @auth(level: USER) {
        user(key: {uid_expr: "auth.uid"}) {
            id,
            name
        }
    }`;

// Impersonate a user with the specified auth claims
const optionsAuthenticated: GraphqlOptions<undefined> = {
    impersonate: {
        authClaims: {
            sub: 'QVBJcy5ndXJ1'
        }
    }
};

// executeGraphql with impersonated authenticated user scope
const gqlResponse = await dataConnect.executeGraphql<UserData, undefined>(queryGetUserImpersonation, optionsAuthenticated);

// gqlResponse -> { "data": { "user": { "id": "QVBJcy5ndXJ1", "name": "Fred" } } }

Yönetici kimlik bilgilerini kullanma

Yönetici düzeyinde izinler gerektiren bir işlem yapıyorsanız çağrıdan kimliğe bürünme parametresini çıkarın:

// User can be publicly accessible, or restricted to admins
const query = "query getProfile(id: AuthID) { user(id: $id) { id name } }";

interface UserData {
  user: {
    id: string;
    name: string;
  };
}

export interface UserVariables {
  id: string;
}

const options:GraphqlOptions<UserVariables> = { variables: { id: "QVBJcy5ndXJ1" } };

// executeGraphql
const gqlResponse = await dataConnect.executeGraphql<UserData, UserVariables>(query, options);

// executeGraphqlRead (similar to previous sample but only for read operations)
const gqlResponse = await dataConnect.executeGraphqlRead<UserData, UserVariables>(query, options);

// gqlResponse -> { "data": { "user": { "id": "QVBJcy5ndXJ1", "name": "Fred" } } }

Bu şekilde çağrılan bir işlem, veritabanına tam erişime sahiptir. Yalnızca yönetim amaçlarıyla kullanılmak üzere tasarlanmış sorgularınız veya mutasyonlarınız varsa bunları @auth(level: NO_ACCESS) yönergesiyle tanımlamanız gerekir. Bu sayede, yalnızca yönetici düzeyindeki arayanların bu işlemleri gerçekleştirebilmesi sağlanır.

Toplu veri ekleme işlemleri gerçekleştirme

Firebase, üretim veritabanlarında toplu veri işlemleri için Admin SDK kullanılmasını önerir.

SDK, toplu verilerle çalışmak için aşağıdaki yöntemleri sağlar. Her yöntem, sağlanan bağımsız değişkenlerden bir GraphQL mutasyonu oluşturur ve yürütür.


// Methods of the bulk operations API
// dc is a SQL Connect admin instance from getDataConnect

const resp = await dc.insert("movie" /*table name*/, data[0]);
const resp = await dc.insertMany("movie" /*table name*/, data);
const resp = await dc.upsert("movie" /*table name*/, data[0]);
const resp = await dc.upsertMany("movie" /*table name*/, data);

İç içe yerleştirilmiş ilişkisel işlemler (bire çok)

Admin SDK, toplu işlemlerde ilişkisel verileri destekler:

// Example of inserting a movie with nested reviews
const moviesData = [
  {
    title: "Interstellar",
    genre: "Sci-Fi",
    reviews_on_movie: [
      {
        rating: 5,
        reviewText: "Visually stunning and emotionally powerful.",
        user: { id: "user-789" }
      }
    ]
  }
];

// Atomically insert movies and their reviews in a single database round-trip.
const response = await dc.insertMany("movie", moviesData);

Toplu işlemlerle ilgili performans notları

Arka uca yapılan her istek için Cloud SQL'ya bir gidiş-dönüş yolculuğu yapılır. Bu nedenle, ne kadar çok toplu istek gönderirseniz işleme hızı da o kadar yüksek olur.

Ancak grup boyutu ne kadar büyük olursa oluşturulan SQL ifadesi de o kadar uzun olur. PostgreSQL SQL ifadesi uzunluk sınırı aşıldığında bir hatayla karşılaşırsınız.

Uygulamada, iş yükünüz için uygun grup boyutunu bulmak üzere denemeler yapın.

Sırada ne var?