Uzantı oluşturmaya başlayın

Bu sayfada, projenize yükleyebileceğiniz veya başkalarıyla paylaşabileceğiniz basit bir Firebase uzantısı oluşturmak için gereken adımlarda size yol gösterilmektedir. Bu basit Firebase uzantısı örneği, Realtime Database'nizde mesajları izler ve bunları büyük harfe dönüştürür.

1. Ortamınızı ayarlama ve projeyi ilk kullanıma hazırlama

Uzantı oluşturmaya başlamadan önce gerekli araçlarla bir derleme ortamı oluşturmanız gerekir.

  1. Node.js 16 veya daha yeni bir sürümü yükleyin. Node'u yüklemenin bir yolu nvm (veya nvm-windows) kullanmaktır.

  2. Firebase CLI'yi yükleyin veya en son sürümüne güncelleyin. npm kullanarak yüklemek veya güncellemek için şu komutu çalıştırın:

    npm install -g firebase-tools
    

Ardından, yeni bir uzantı projesini başlatmak için Firebase CLI'yi kullanın:

  1. Uzantınız için bir dizin oluşturun ve bu dizine cd ekleyin:

    mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
    
  2. Firebase CLI'nin ext:dev:init komutunu çalıştırın:

    firebase ext:dev:init
    

    İstendiğinde, işlevler için JavaScript'i seçin (ancak kendi uzantınızı geliştirirken TypeScript'i de kullanabileceğinizi unutmayın) ve bağımlılıkların yüklenmesi istendiğinde "evet" yanıtını verin. (Diğer seçenekler için varsayılan değerleri kabul edin.) Bu komut, yeni bir uzantı için iskelet kod tabanı oluşturur. Bu kod tabanını kullanarak uzantınızı geliştirmeye başlayabilirsiniz.

2. Emülatör kullanarak örnek uzantıyı deneme

Firebase CLI, yeni uzantılar dizini başlattığında basit bir örnek işlev ve Firebase emülatör paketini kullanarak bir uzantıyı çalıştırmak için gerekli dosyaları içeren bir integration-tests dizini oluşturdu.

Örnek uzantıyı emülatörde çalıştırmayı deneyin:

  1. integration-tests dizinine geçin:

    cd functions/integration-tests
    
  2. Emülatörü bir demo projeyle başlatın:

    firebase emulators:start --project=demo-test
    

    Emülatör, uzantıyı önceden tanımlanmış bir "sahte" projeye (demo-test) yükler. Uzantıda şu ana kadar, erişildiğinde "merhaba dünya" mesajı döndüren tek bir HTTP tarafından tetiklenen işlev (greetTheWorld) bulunmaktadır.

  3. Emülatör hâlâ çalışırken, uzantıyı başlattığınızda yazdırdığı URL'yi ziyaret ederek greetTheWorld işlevini deneyin.

    Tarayıcınızda "Merhaba Dünya from greet-the-world" mesajı gösterilir.

  4. Bu işlevin kaynak kodu, uzantının functions dizinindedir. Kaynağı, tercih ettiğiniz düzenleyicide veya IDE'de açın:

    functions/index.js

    const functions = require("firebase-functions/v1");
    
    exports.greetTheWorld = functions.https.onRequest((req, res) => {
      // Here we reference a user-provided parameter
      // (its value is provided by the user during installation)
      const consumerProvidedGreeting = process.env.GREETING;
    
      // And here we reference an auto-populated parameter
      // (its value is provided by Firebase after installation)
      const instanceId = process.env.EXT_INSTANCE_ID;
    
      const greeting = `${consumerProvidedGreeting} World from ${instanceId}`;
    
      res.send(greeting);
    });
    
  5. Emülatör çalışırken Functions kodunuzda yaptığınız değişiklikleri otomatik olarak yeniden yükler. greetTheWorld işlevinde küçük bir değişiklik yapmayı deneyin:

    functions/index.js

    const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
    

    Yaptığınız değişiklikleri kaydedin. Emülatör, kodunuzu yeniden yükler. Artık işlev URL'sini ziyaret ettiğinizde güncellenmiş karşılama mesajını görürsünüz.

3. extension.yaml dosyasına temel bilgileri ekleme

Geliştirme ortamınızı oluşturdunuz ve uzantı emülatörünü çalıştırıyorsunuz. Artık kendi uzantınızı yazmaya başlayabilirsiniz.

İlk adım olarak, önceden tanımlanmış uzantı meta verilerini greet-the-world yerine yazmak istediğiniz uzantıyı yansıtacak şekilde düzenleyin. Bu meta veriler extension.yaml dosyasında depolanır.

  1. Düzenleyicinizde extension.yaml dosyasını açın ve dosyanın tüm içeriğini aşağıdakiyle değiştirin:

    name: rtdb-uppercase-messages
    version: 0.0.1
    specVersion: v1beta  # Firebase Extensions specification version; don't change
    
    # Friendly display name for your extension (~3-5 words)
    displayName: Convert messages to upper case
    
    # Brief description of the task your extension performs (~1 sentence)
    description: >-
      Converts messages in RTDB to upper case
    
    author:
      authorName: Your Name
      url: https://your-site.example.com
    
    license: Apache-2.0  # Required license
    
    # Public URL for the source code of your extension
    sourceUrl: https://github.com/your-name/your-repo
    

    name alanında kullanılan adlandırma kuralına dikkat edin: Resmi Firebase uzantıları, uzantının çalıştığı birincil Firebase ürününü belirten bir ön ek ve ardından uzantının ne yaptığının açıklamasıyla adlandırılır. Kendi uzantılarınızda da aynı kuralı uygulamanız gerekir.

  2. Uzantı adınızı değiştirdiğiniz için emülatör yapılandırmanızı da yeni adla güncellemeniz gerekir:

    1. functions/integration-tests/firebase.json dosyasında greet-the-world değerini rtdb-uppercase-messages olarak değiştirin.
    2. functions/integration-tests/extensions/greet-the-world.envfunctions/integration-tests/extensions/rtdb-uppercase-messages.env olarak yeniden adlandırın.

Uzantı kodunuzda greet-the-world uzantısının bazı kalıntıları var ancak şimdilik bunları kaldırmayın. Bu bilgileri sonraki birkaç bölümde güncelleyeceksiniz.

4. Cloud Functions işlevi yazın ve uzantı kaynağı olarak tanımlayın

Artık kod yazmaya başlayabilirsiniz. Bu adımda, uzantınızın temel görevini (Realtime Database'de mesajları izlemek ve bunları büyük harfe dönüştürmek) gerçekleştiren bir Cloud Function yazacaksınız.

  1. Uzantının işlevlerinin kaynağını (uzantının functions dizininde) tercih ettiğiniz düzenleyicide veya IDE'de açın. İçeriğini aşağıdakiyle değiştirin:

    functions/index.js

    import { database, logger } from "firebase-functions/v1";
    
    const app = initializeApp();
    
    // Listens for new messages added to /messages/{pushId}/original and creates an
    // uppercase version of the message to /messages/{pushId}/uppercase
    // for all databases in 'us-central1'
    export const makeuppercase = database
      .ref("/messages/{pushId}/uppercase")
      .onCreate(async (snapshot, context) => {
        // Grab the current value of what was written to the Realtime Database.
        const original = snapshot.val();
    
        // Convert it to upper case.
        logger.log("Uppercasing", context.params.pushId, original);
        const uppercase = original.toUpperCase();
    
        // Setting an "uppercase" sibling in the Realtime Database.
        const upperRef = snapshot.ref.parent.child("upper");
        await upperRef.set(uppercase);
    });
    

    Değiştirdiğiniz eski işlev, bir HTTP uç noktasına erişildiğinde çalışan HTTP tetiklemeli bir işlevdi. Yeni işlev, gerçek zamanlı veritabanı etkinlikleri tarafından tetiklenir: Belirli bir yolda yeni öğeler izler ve bir öğe algılandığında değerin büyük harfli sürümünü veritabanına geri yazar.

    Bu arada, bu yeni dosyada CommonJS (require) yerine ECMAScript modülü söz dizimi (import ve export) kullanılmaktadır. Node'da ES modüllerini kullanmak için functions/package.json içinde "type": "module" değerini belirtin:

    {
      "name": "rtdb-uppercase-messages",
      "main": "index.js",
      "type": "module",
      …
    }
    
  2. Uzantınızdaki her işlev, extension.yaml dosyasında tanımlanmalıdır. Örnek uzantı, uzantının tek Cloud işlevi olarak greetTheWorld'ü tanımladı. Artık greetTheWorld ile değiştirdiğiniz bu işlevin tanımını da güncellemeniz gerekiyor.makeuppercase

    extension.yaml dosyasını açın ve bir resources alanı ekleyin:

    resources:
      - name: makeuppercase
        type: firebaseextensions.v1beta.function
        properties:
          eventTrigger:
            eventType: providers/google.firebase.database/eventTypes/ref.create
            # DATABASE_INSTANCE (project's default instance) is an auto-populated
            # parameter value. You can also specify an instance.
            resource: projects/_/instances/${DATABASE_INSTANCE}/refs/messages/{pushId}/original
          runtime: "nodejs18"
    
  3. Uzantı artık tetikleyici olarak Realtime Database kullandığından, emülatör yapılandırmanızı Cloud Functions emülatörünün yanı sıra RTDB emülatörünü de çalıştıracak şekilde güncellemeniz gerekir:

    1. Emülatör hâlâ çalışıyorsa Ctrl-C tuşlarına basarak durdurun.

    2. functions/integration-tests dizininden aşağıdaki komutu çalıştırın:

      firebase init emulators
      

      İstendiğinde varsayılan proje oluşturma adımını atlayıp Functions ve veritabanı emülatörlerini seçin. Varsayılan bağlantı noktalarını kabul edin ve kurulum aracının gerekli dosyaları indirmesine izin verin.

    3. Emülatörü yeniden başlatın:

      firebase emulators:start --project=demo-test
      
  4. Güncellenen uzantınızı deneyin:

    1. Emülatörü başlattığınızda yazdırılan bağlantıyı kullanarak veritabanı emülatör kullanıcı arayüzünü açın.

    2. Veritabanının kök düğümünü düzenleyin:

      • Alan: messages
      • Tür: json
      • Değer: {"11": {"original": "recipe"}}

      Her şey doğru şekilde ayarlandıysa veritabanı değişikliklerinizi kaydettiğinizde uzantının makeuppercase işlevi tetiklenir ve 11. iletiye "upper": "RECIPE" içeriğini içeren bir alt kayıt eklenir. Beklenen sonuçları doğrulamak için emülatör kullanıcı arayüzünün günlüklerine ve veritabanı sekmelerine göz atın.

    3. messages düğümüne ({"original":"any text"}) daha fazla alt öğe eklemeyi deneyin. Yeni bir kayıt eklediğinizde uzantı, original alanının büyük harfli içeriğini içeren bir uppercase alanı ekler.

Artık bir RTDB örneğinde çalışan basit ancak eksiksiz bir uzantınız var. Sonraki bölümlerde, bu uzantıyı bazı ek özelliklerle hassaslaştıracaksınız. Ardından, uzantıyı başkalarına dağıtmaya hazır hale getirir ve son olarak uzantınızı Uzantıları Merkezi'nde nasıl yayınlayacağınızı öğrenirsiniz.

5. API'leri ve rolleri tanımlama

Firebase, yüklü bir uzantının her örneğine örnek başına bir hizmet hesabı kullanarak projeye ve verilerine sınırlı erişim izni verir. Her hesap, çalışması için gereken minimum izin grubuna sahiptir. Bu nedenle, uzantınızın gerektirdiği IAM rollerini açıkça belirtmeniz gerekir. Kullanıcılar uzantınızı yüklediğinde Firebase, bu rollerin verildiği bir hizmet hesabı oluşturur ve uzantıyı çalıştırmak için bu hesabı kullanır.

Bir ürünün etkinliklerini tetiklemek için rol belirtmeniz gerekmez ancak ürünle başka bir şekilde etkileşim kurmak için rol belirtmeniz gerekir. Son adımda eklediğiniz işlev Realtime Database'e yazdığı için extension.yaml değişkenine aşağıdaki beyanı eklemeniz gerekir:

roles:
  - role: firebasedatabase.admin
    reason: Allows the extension to write to RTDB.

Benzer şekilde, bir uzantının kullandığı Google API'lerini apis alanında belirtirsiniz. Kullanıcılar uzantınızı yüklediğinde, bu API'leri projeleri için otomatik olarak etkinleştirmek isteyip istemedikleri sorulur. Bu genellikle yalnızca Firebase dışı Google API'leri için gereklidir ve bu kılavuzda gerekli değildir.

6. Kullanıcı tarafından yapılandırılabilen parametreleri tanımlama

Son iki adımda oluşturduğunuz işlev, gelen mesajlar için belirli bir RTDB konumunu izledi. Bazen belirli bir konumu izlemek isteyebilirsiniz. Örneğin, uzantınız yalnızca uzantınız için kullandığınız bir veritabanı yapısında çalışıyorsa. Ancak çoğu zaman bu değerleri, uzantınızı projelerine yükleyen kullanıcılar tarafından yapılandırılabilir hale getirmek istersiniz. Bu sayede kullanıcılar, mevcut veritabanı kurulumlarıyla çalışmak için uzantınızı kullanabilir.

Uzantı için yeni mesajları izleyeceği yolu kullanıcı tarafından yapılandırılabilir hale getirin:

  1. extension.yaml dosyasına bir params bölümü ekleyin:

    - param: MESSAGE_PATH
      label: Message path
      description: >-
        What is the path at which the original text of a message can be found?
      type: string
      default: /messages/{pushId}/original
      required: true
      immutable: false
    

    Bu, kullanıcıların uzantınızı yüklerken ayarlamaları istenen yeni bir dize parametresi tanımlar.

  2. extension.yaml dosyasında makeuppercase beyanınıza dönün ve resource alanını aşağıdaki şekilde değiştirin:

    resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
    

    ${param:MESSAGE_PATH} jetonu, az önce tanımladığınız parametreye referans verir. Uzantı çalıştırıldığında bu jeton, kullanıcının söz konusu parametre için yapılandırdığı değerle değiştirilir. Böylece makeuppercase işlevi, kullanıcının belirttiği yolu dinler. extension.yaml'ün (ve POSTINSTALL.md'un - daha sonra bu konu hakkında daha fazla bilgi verilecektir) herhangi bir yerinde kullanıcı tanımlı bir parametreye referans vermek için bu söz dizimini kullanabilirsiniz.

  3. Kullanıcı tanımlı parametrelere işlev kodunuzdan da erişebilirsiniz.

    Son bölümde yazdığınız işlevde, değişiklikleri izlemek için yolu sabit kodladınız. Tetikleyici tanımını, kullanıcı tanımlı değere referans verecek şekilde değiştirin:

    functions/index.js

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
    

    Firebase Extensions'de bu değişikliğin yalnızca dokümantasyon amacıyla yapıldığını unutmayın: Bir Cloud Functions, uzantı kapsamında dağıtıldığında extension.yaml dosyasında bulunan tetikleyici tanımını kullanır ve işlev tanımında belirtilen değeri yoksayar. Yine de bu değerin nereden geldiğini kodunuzda belirtmeniz iyi bir fikirdir.

  4. Çalışma zamanında etkisi olmayan bir kod değişikliği yapmak can sıkıcı olabilir. Ancak buradan çıkarabileceğiniz önemli bir ders, işlev kodunuzdaki kullanıcı tanımlı parametrelere erişebileceğiniz ve bunları işlevin mantığında sıradan bir değer olarak kullanabileceğinizdir. Bu özelliğin bir göstergesi olarak, kullanıcının tanımladığı değere gerçekten eriştiğinizi göstermek için aşağıdaki günlük ifadesini ekleyin:

    functions/index.js

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate(
      async (snapshot, context) => {
        logger.log("Found new message at ", snapshot.ref);
    
        // Grab the current value of what was written to the Realtime Database.
        ...
    
  5. Normalde, kullanıcılardan uzantı yüklerken parametreler için değer sağlamaları istenir. Ancak test ve geliştirme için emülatör kullandığınızda yükleme işlemini atlarsınız. Bu nedenle, kullanıcı tanımlı parametreler için bir env dosyası kullanarak değerler sağlarsınız.

    functions/integration-tests/extensions/rtdb-uppercase-messages.env dosyasını açın ve GREETING tanımını aşağıdakiyle değiştirin:

    MESSAGE_PATH=/msgs/{pushId}/original
    

    Yukarıdaki yolun, varsayılan yoldan ve daha önce tanımladığınız yoldan farklı olduğunu unutmayın. Bu, güncellenmiş uzantınızı denediğinizde tanımınızın geçerli olduğunu kendinize kanıtlamak içindir.

  6. Ardından, emülatörü yeniden başlatın ve veritabanı emülatörü kullanıcı arayüzünü tekrar ziyaret edin.

    Yukarıda tanımladığınız yolu kullanarak veritabanının kök düğümünü düzenleyin:

    • Alan: msgs
    • Tür: json
    • Değer: {"11": {"original": "recipe"}}

    Veritabanı değişikliklerinizi kaydettiğinizde, uzantının makeuppercase işlevi önceki gibi tetiklenir ancak artık kullanıcı tanımlı parametreyi konsol günlüğüne de yazdırır.

7. Kullanıcı tanımlı mantık için etkinlik kancaları sağlayın

Bir Firebase ürünü, uzantı yazarları tarafından sağlanan mantığı nasıl tetikleyebilir? Bunu daha önce görmüştünüz: Realtime Database'de yeni kayıt oluşturulması makeuppercase işlevinizi tetikler. Uzantınız, uzantınızı yükleyen kullanıcılarla benzer bir ilişkiye sahip olabilir: Uzantınız, kullanıcı tarafından tanımlanan mantığı tetikleyebilir.

Bir uzantı, eşzamanlı kanca, eşzamansız kanca veya her ikisini de sağlayabilir. Senkronize kancalar, kullanıcılara uzantının işlevlerinden birinin tamamlanmasını engelleyen görevleri gerçekleştirme olanağı sunar. Bu, örneğin, kullanıcılara bir uzantı işini yapmadan önce özel ön işleme yapmanın bir yolunu sunmak için yararlı olabilir.

Bu kılavuzda, uzantınıza bir asenkron kanca ekleyeceksiniz. Bu kanca, kullanıcıların uzantınız büyük harfli mesajı Realtime Database'e yazdıktan sonra çalıştırılacak kendi işleme adımlarını tanımlamalarını sağlar. Asenkron kancalar, kullanıcı tanımlı işlevleri tetiklemek için Eventarc'ı kullanır. Uzantılar, yayınladıkları etkinlik türlerini belirtir ve kullanıcılar uzantıyı yüklediklerinde ilgilendikleri etkinlik türlerini seçerler. Kullanıcı en az bir etkinlik seçerse Firebase, yükleme işleminin bir parçası olarak uzantı için bir Eventarc kanalı oluşturur. Kullanıcılar daha sonra bu kanalda dinleyen ve uzantı yeni etkinlikler yayınladığında tetiklenen kendi bulut işlevlerini dağıtabilir.

Asenkron kanca eklemek için aşağıdaki adımları uygulayın:

  1. extension.yaml dosyasına, uzantının yayınladığı tek etkinlik türünü açıklayan aşağıdaki bölümü ekleyin:

    events:
      - type: test-publisher.rtdb-uppercase-messages.v1.complete
        description: >-
          Occurs when message uppercasing completes. The event subject will contain
          the RTDB URL of the uppercase message.
    

    Etkinlik türleri evrensel olarak benzersiz olmalıdır. Benzersizliği sağlamak için etkinliklerinizi her zaman aşağıdaki biçimi kullanarak adlandırın: <publisher-id>.<extension-id>.<version>.<description>. (Henüz yayıncı kimliğiniz olmadığı için şimdilik test-publisher değerini kullanın.)

  2. makeuppercase işlevinin sonuna, az önce tanımladığınız türde bir etkinlik yayınlayan kod ekleyin:

    functions/index.js

    // Import the Eventarc library:
    import { initializeApp } from "firebase-admin/app";
    import { getEventarc } from "firebase-admin/eventarc";
    
    const app = initializeApp();
    
    // In makeuppercase, after upperRef.set(uppercase), add:
    
    // Set eventChannel to a newly-initialized channel, or `undefined` if events
    // aren't enabled.
    const eventChannel =
      process.env.EVENTARC_CHANNEL &&
      getEventarc().channel(process.env.EVENTARC_CHANNEL, {
        allowedEventTypes: process.env.EXT_SELECTED_EVENTS,
      });
    
    // If events are enabled, publish a `complete` event to the configured
    // channel.
    eventChannel &&
      eventChannel.publish({
        type: "test-publisher.rtdb-uppercase-messages.v1.complete",
        subject: upperRef.toString(),
        data: {
          "original": original,
          "uppercase": uppercase,
        },
      });
    

    Bu örnek kod, EVENTARC_CHANNEL ortam değişkeninin yalnızca kullanıcı en az bir etkinlik türünü etkinleştirdiğinde tanımlanmasından yararlanır. EVENTARC_CHANNEL tanımlanmazsa kod herhangi bir etkinlik yayınlamaya çalışmaz.

    Eventarc etkinliklerine ek bilgiler ekleyebilirsiniz. Yukarıdaki örnekte, etkinlikte yeni oluşturulan değere referans içeren bir subject alanı ve orijinal ve büyük harfli mesajları içeren bir data yükü vardır. Etkinliği tetikleyen kullanıcı tanımlı işlevler bu bilgileri kullanabilir.

  3. Normalde EVENTARC_CHANNEL ve EXT_SELECTED_EVENTS ortam değişkenleri, kullanıcının yükleme sırasında seçtiği seçeneklere göre tanımlanır. Emülatörle test etmek için rtdb-uppercase-messages.env dosyasında aşağıdaki değişkenleri manuel olarak tanımlayın:

    EVENTARC_CHANNEL=locations/us-central1/channels/firebase
    EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
    

Bu noktada, uzantınıza asenkron etkinlik kancası eklemek için gereken adımları tamamlamış olursunuz.

Yeni uygulamanız olan bu özelliği denemek için sonraki birkaç adımda uzantıyı yükleyen bir kullanıcı rolüne bürünün:

  1. functions/integration-tests dizininden yeni bir Firebase projesini başlatın:

    firebase init functions
    

    İstendiğinde varsayılan proje oluşturmayı reddedin, Cloud Functions dili olarak JavaScript'i seçin ve gerekli bağımlılıkları yükleyin. Bu proje, uzantınızın yüklü olduğu bir kullanıcı projesini temsil eder.

  2. integration-tests/functions/index.js dosyasını düzenleyin ve aşağıdaki kodu yapıştırın:

    import { logger } from "firebase-functions/v1";
    import { onCustomEventPublished } from "firebase-functions/v2/eventarc";
    
    import { initializeApp } from "firebase-admin/app";
    import { getDatabase } from "firebase-admin/database";
    
    const app = initializeApp();
    
    export const extraemphasis = onCustomEventPublished(
      "test-publisher.rtdb-uppercase-messages.v1.complete",
      async (event) => {
        logger.info("Received makeuppercase completed event", event);
    
        const refUrl = event.subject;
        const ref = getDatabase().refFromURL(refUrl);
        const upper = (await ref.get()).val();
        return ref.set(`${upper}!!!`);
      }
    );
    

    Bu, kullanıcının yazabileceği bir son işleme işlevi örneğidir. Bu durumda işlev, uzantının complete etkinliği yayınlamasını bekler ve tetiklendiğinde yeni büyük harflerle yazılmış mesaja üç ünlem işareti ekler.

  3. Emülatörü yeniden başlatın. Emülatör, uzantının işlevlerini ve "kullanıcı"nın tanımladığı son işleme işlevini yükler.

  4. Veritabanı emülatör kullanıcı arayüzünü ziyaret edin ve yukarıda tanımladığınız yolu kullanarak veritabanının kök düğümünü düzenleyin:

    • Alan:msgs
    • Tür: json
    • Değer: {"11": {"original": "recipe"}}

    Veritabanı değişikliklerinizi kaydettiğinizde, uzantının makeuppercase işlevi ve kullanıcının extraemphasis işlevi sırayla tetiklenir. Bu da upper alanının RECIPE!!! değerini almasına neden olur.

8. Yaşam döngüsü etkinlik işleyicileri ekleme

Şu ana kadar yazdığınız uzantı, mesajları oluşturuldukları sırada işler. Peki kullanıcılarınız uzantıyı yüklediğinde zaten bir ileti veritabanı varsa ne olur? Firebase Extensions'te, uzantınız yüklendiğinde, güncellendiğinde veya yeniden yapılandırıldığında işlemleri tetiklemek için kullanabileceğiniz yaşam döngüsü etkinliği kancaları adlı bir özellik bulunur. Bu bölümde, bir kullanıcı uzantınızı yüklediğinde projenin mevcut mesaj veritabanını büyük harfli mesajlarla doldurmak için yaşam döngüsü etkinliği kancalarını kullanacaksınız.

Firebase uzantıları, yaşam döngüsü etkinlik işleyicilerinizi çalıştırmak için Cloud Tasks'i kullanır. Cloud Functions'i kullanarak etkinlik işleyicileri tanımlarsınız. Uzantı örneğiniz desteklenen yaşam döngüsü etkinliklerinden birine ulaştığında, bir işleyici tanımladıysanız işleyici bir Cloud Görevler kuyruğuna eklenir. Ardından Cloud Tasks, işleyiciyi eşzamansız olarak yürütür. Bir yaşam döngüsü etkinlik işleyici çalışırken Firebase konsolu, kullanıcıya uzantı örneğinde devam eden bir işleme görevi olduğunu bildirir. Devam eden durumu ve görev tamamlandığında durumu kullanıcıya bildirmek, işleyici işlevinize bağlıdır.

Mevcut mesajları dolduran bir yaşam döngüsü etkinlik işleyicisi eklemek için aşağıdakileri yapın:

  1. Görev kuyruğu etkinlikleri tarafından tetiklenen yeni bir Cloud Functions işlevi tanımlayın:

    functions/index.js

    import { tasks } from "firebase-functions/v1";
    
    import { getDatabase } from "firebase-admin/database";
    import { getExtensions } from "firebase-admin/extensions";
    import { getFunctions } from "firebase-admin/functions";
    
    export const backfilldata = tasks.taskQueue().onDispatch(async () => {
      const batch = await getDatabase()
        .ref(process.env.MESSAGE_PATH)
        .parent.parent.orderByChild("upper")
        .limitToFirst(20)
        .get();
    
      const promises = [];
      for (const key in batch.val()) {
        const msg = batch.child(key);
        if (msg.hasChild("original") && !msg.hasChild("upper")) {
          const upper = msg.child("original").val().toUpperCase();
          promises.push(msg.child("upper").ref.set(upper));
        }
      }
      await Promise.all(promises);
    
      if (promises.length > 0) {
        const queue = getFunctions().taskQueue(
          "backfilldata",
          process.env.EXT_INSTANCE_ID
        );
        return queue.enqueue({});
      } else {
        return getExtensions()
          .runtime()
          .setProcessingState("PROCESSING_COMPLETE", "Backfill complete.");
      }
    });
    

    İşlevin, kendisini görev kuyruğuna geri eklemeden önce yalnızca birkaç kaydı işlediğine dikkat edin. Bu, bir Cloud Function'ın zaman aşımı aralığı içinde tamamlanamayan işlem görevlerini ele almak için yaygın olarak kullanılan bir stratejidir. Bir kullanıcı uzantınızı yüklediğinde veritabanında kaç mesajının olabileceğini tahmin edemeyeceğiniz için bu strateji uygundur.

  2. extension.yaml dosyasında, doldurma işlevinizi taskQueueTrigger mülküne sahip bir uzantı kaynağı olarak beyan edin:

    resources:
      - name: makeuppercase
        ...
      - name: backfilldata
        type: firebaseextensions.v1beta.function
        description: >-
          Backfill existing messages with uppercase versions
        properties:
          runtime: "nodejs18"
          taskQueueTrigger: {}
    

    Ardından işlevi onInstall yaşam döngüsü etkinliğinin işleyicisi olarak tanımlayın:

    lifecycleEvents:
      onInstall:
        function: backfilldata
        processingMessage: Uppercasing existing messages
    
  3. Mevcut mesajları doldurmak iyi bir özellik olsa da uzantı bu olmadan da çalışabilir. Bu gibi durumlarda, yaşam döngüsü etkinlik işleyicilerinin çalıştırılmasını isteğe bağlı hale getirmeniz gerekir.

    Bunu yapmak için extension.yaml parametresine yeni bir parametre ekleyin:

    - param: DO_BACKFILL
      label: Backfill existing messages
      description: >-
        Generate uppercase versions of existing messages?
      type: select
      required: true
      options:
        - label: Yes
          value: true
        - label: No
          value: false
    

    Ardından, doldurma işlevinin başında DO_BACKFILL parametresinin değerini kontrol edin ve ayarlanmamışsa erken çıkın:

    functions/index.js

    if (!process.env.DO_BACKFILL) {
      return getExtensions()
        .runtime()
        .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped.");
    }
    

Yukarıdaki değişikliklerle birlikte, uzantı artık yüklendiğinde mevcut mesajları büyük harfe dönüştürecek.

Bu noktaya kadar uzantınızı geliştirmek ve devam eden değişiklikleri test etmek için uzantı emülatörünü kullandınız. Ancak uzantı emülatörü yükleme işlemini atlar. Bu nedenle, onInstall etkinlik işleyicinizi test etmek için uzantıyı gerçek bir projeye yüklemeniz gerekir. Bu otomatik doldurma özelliğinin eklenmesiyle eğitim uzantısı artık kod olarak tamamlanmış oldu.

9. Gerçek bir Firebase projesine dağıtma

Uzantı emülatörü, geliştirme sırasında bir uzantıda hızlı iterasyon yapmak için mükemmel bir araç olsa da bir noktada bunu gerçek bir projede denemek isteyeceksiniz.

Bunu yapmak için önce bazı hizmetlerin etkin olduğu yeni bir proje oluşturun:

  1. Firebase konsolunda yeni bir proje ekleyin.
  2. Projenizi, kullandıkça öde Blaze planına yükseltin. Firebase için Cloud Functions, projenizin faturalandırma hesabına sahip olmasını gerektirir. Bu nedenle, uzantı yüklemek için de faturalandırma hesabınız olmalıdır.
  3. Yeni projenizde Gerçek Zamanlı Veritabanı'nı etkinleştirin.
  4. Uzantılarınızın yükleme sırasında mevcut verileri doldurma özelliğini test etmek istediğiniz için gerçek zamanlı veritabanı örneğinize bazı örnek verileri aktarın:
    1. Bazı tohum RTDB verilerini indirin.
    2. Firebase konsolunun Gerçek Zamanlı Veritabanı sayfasında (diğer) > JSON'u İçe Aktar'ı tıklayın ve az önce indirdiğiniz dosyayı seçin.
  5. orderByChild yöntemini kullanacak şekilde doldurma işlevini etkinleştirmek için veritabanını, mesajları upper değerine göre dizine ekleyecek şekilde yapılandırın:

    {
      "rules": {
        ".read": false,
        ".write": false,
        "messages": {
          ".indexOn": "upper"
        }
      }
    }
    

Ardından, uzantınızı yerel kaynaktan yeni projeye yükleyin:

  1. Firebase projeniz için yeni bir dizin oluşturun:

    mkdir ~/extensions-live-test && cd ~/extensions-live-test
    
  2. Çalışma dizininde bir Firebase projesini başlatın:

    firebase init database
    

    İstendiğinde, yeni oluşturduğunuz projeyi seçin.

  3. Uzantı yükleme işlemini yerel Firebase projenize uygulayın:

    firebase ext:install /path/to/rtdb-uppercase-messages
    

    Firebase CLI aracını kullanarak uzantı yüklerken kullanıcı deneyiminin nasıl olduğunu burada görebilirsiniz. Yapılandırma aracı mevcut veritabanınızı doldurmak isteyip istemediğinizi sorduğunda "evet"i seçtiğinizden emin olun.

    Yapılandırma seçeneklerini seçtikten sonra Firebase KSA, yapılandırmanızı extensions dizinine kaydeder ve uzantı kaynak konumunu firebase.json dosyasına yazar. Bu iki kayıt birlikte uzantı manifesti olarak adlandırılır. Kullanıcılar, uzantı yapılandırmalarını kaydetmek ve farklı projelere dağıtmak için manifest'i kullanabilir.

  4. Uzantı yapılandırmanızı yayındaki projenize dağıtın:

    firebase deploy --only extensions
    

Her şey yolunda giderse Firebase CLI, uzantınızı projenize yükleyip yükler. Yükleme tamamlandıktan sonra doldurma görevi çalıştırılır ve birkaç dakika içinde veritabanınız büyük harfli mesajlarla güncellenir. İleti veritabanına yeni düğümler ekleyin ve uzantının yeni iletiler için de çalıştığından emin olun.

10. Doküman yazma

Uzantınızı kullanıcılarla paylaşmadan önce, başarılı olmaları için yeterli doküman sağladığınızdan emin olun.

Uzantı projesini başlattığınızda Firebase CLI, gerekli minimum dokümanların taslak sürümlerini oluşturdu. Bu dosyaları, oluşturduğunuz uzantıyı doğru yansıtacak şekilde güncelleyin.

extension.yaml

Bu uzantıyı geliştirirken bu dosyayı zaten güncellediğiniz için şu anda başka bir güncelleme yapmanız gerekmez.

Ancak bu dosyada bulunan dokümanların önemini göz ardı etmeyin. extension.yaml dosyası, bir uzantının önemli tanımlayıcı bilgilerine (ad, açıklama, yazar, resmi depo konumu) ek olarak her kaynak ve kullanıcı tarafından yapılandırılabilir parametre için kullanıcılara yönelik dokümanlar içerir. Bu bilgiler Firebase konsolunda, Uzantı Merkezi'nde ve Firebase KSA'da kullanıcılara gösterilir.

PREINSTALL.md

Bu dosyada, kullanıcının uzantınızı yüklemeden önce ihtiyaç duyduğu bilgileri sağlayın: Uzantının ne yaptığını kısaca açıklayın, ön koşulları açıklayın ve kullanıcıya uzantıyı yüklemenin faturalandırmayla ilgili sonuçları hakkında bilgi verin. Ek bilgiler içeren bir web siteniz varsa buraya bağlantısını ekleyebilirsiniz.

Bu dosyanın metni, kullanıcıya Uzantı Merkezi'nde ve firebase ext:info komutuyla gösterilir.

Aşağıda bir PREINSTALL dosyası örneği verilmiştir:

Use this extension to automatically convert strings to upper case when added to
a specified Realtime Database path.

This extension expects a database layout like the following example:

    "messages": {
      MESSAGE_ID: {
        "original": MESSAGE_TEXT
      },
      MESSAGE_ID: {
        "original": MESSAGE_TEXT
      },
    }

When you create new string records, this extension creates a new sibling record
with upper-cased text:

    MESSAGE_ID: {
      "original": MESSAGE_TEXT,
      "upper": UPPERCASE_MESSAGE_TEXT,
    }

#### Additional setup

Before installing this extension, make sure that you've
[set up Realtime Database](https://firebase.google.com/docs/database/quickstart)
in your Firebase project.

#### Billing

To install an extension, your project must be on the
[Blaze (pay as you go) plan](https://firebase.google.com/pricing).

- This extension uses other Firebase and Google Cloud Platform services, which
  have associated charges if you exceed the service's no-cost tier:
  - Realtime Database
  - Cloud Functions (Node.js 10+ runtime)
    [See FAQs](https://firebase.google.com/support/faq#extensions-pricing)
- If you enable events,
  [Eventarc fees apply](https://cloud.google.com/eventarc/pricing).

POSTINSTALL.md

Bu dosya, uzantınızı başarıyla yükleyen kullanıcılar için yararlı bilgiler içerir. Örneğin, takip eden kurulum adımları, uzantının çalışırken gösterildiği bir örnek vb.

POSTINSTALL.md dosyasının içeriği, bir uzantı yapılandırılıp yüklendikten sonra Firebase konsolunda gösterilir. Bu dosyada kullanıcı parametrelerine referans verebilirsiniz. Bu parametreler, yapılandırılan değerlerle değiştirilir.

Eğitim uzantısı için örnek bir yükleme sonrası dosyası aşağıda verilmiştir:

### See it in action

You can test out this extension right away!

1.  Go to your
    [Realtime Database dashboard](https://console.firebase.google.com/project/${param:PROJECT_ID}/database/${param:PROJECT_ID}/data) in the Firebase console.

1.  Add a message string to a path that matches the pattern `${param:MESSAGE_PATH}`.

1.  In a few seconds, you'll see a sibling node named `upper` that contains the
    message in upper case.

### Using the extension

We recommend adding data by pushing -- for example,
`firebase.database().ref().push()` -- because pushing assigns an automatically
generated ID to the node in the database. During retrieval, these nodes are
guaranteed to be ordered by the time they were added. Learn more about reading
and writing data for your platform (iOS, Android, or Web) in the
[Realtime Database documentation](https://firebase.google.com/docs/database/).

### Monitoring

As a best practice, you can
[monitor the activity](https://firebase.google.com/docs/extensions/manage-installed-extensions#monitor)
of your installed extension, including checks on its health, usage, and logs.

CHANGELOG.md

Ayrıca, bir uzantının sürümleri arasında yaptığınız değişiklikleri CHANGELOG.md dosyasında da belgelemeniz gerekir.

Örnek uzantı daha önce hiç yayınlanmadığından değişiklik günlüğünde yalnızca bir giriş vardır:

## Version 0.0.1

Initial release of the _Convert messages to upper case_ extension.

README.md

Çoğu uzantı, uzantının deposunu ziyaret eden kullanıcılar için bir readme dosyası da sağlar. Bu dosyayı manuel olarak yazabilir veya komutu kullanarak bir readme dosyası oluşturabilirsiniz.

Bu kılavuzun amacı doğrultusunda, readme dosyası yazmayı atlayın.

Ek dokümanlar

Yukarıda bahsedilen dokümanlar, kullanıcılara sağlamanız gereken minimum doküman grubudur. Birçok uzantının kullanıcıların başarılı bir şekilde kullanabilmesi için daha ayrıntılı dokümanlara ihtiyacı vardır. Bu durumda, ek dokümanlar yazıp kullanıcıları yönlendirebileceğiniz bir yerde barındırmanız gerekir.

Bu kılavuzun amacı doğrultusunda daha kapsamlı dokümanlar yazmayın.

11. Uzantılar Merkezi'nde yayınlama

Uzantı kodunuz tamamlandı ve dokümante edildi. Artık uzantınızı Uzantı Merkezi'nde dünyayla paylaşmaya hazırsınız. Ancak bu yalnızca bir eğitim olduğu için bunu yapmayın. Burada ve Firebase Extensions yayıncı dokümanlarının geri kalanında öğrendiklerinizi ve Firebase tarafından yazılmış resmi uzantıların kaynak kodunu inceleyerek kendi uzantınızı yazmaya başlayın.

Çalışmanızı Uzantılar Merkezi'nde yayınlamaya hazır olduğunuzda aşağıdaki adımları uygulayın:

  1. İlk uzantınızı yayınlıyorsanız uzantı yayıncısı olarak kaydolun. Uzantı yayıncısı olarak kaydolduğunuzda, kullanıcıların sizi uzantılarınızın yazarı olarak hızlıca tanımlamasına olanak tanıyan bir yayıncı kimliği oluşturursunuz.
  2. Uzantılarınızın kaynak kodunu herkes tarafından doğrulanabilir bir konumda barındırın. Kodunuz doğrulanabilir bir kaynaktan kullanılabilir olduğunda Firebase, uzantınızı doğrudan bu konumdan yayınlayabilir. Bu sayede, uzantınızın şu anda kullanıma sunulan sürümünü yayınladığınızdan emin olabilirsiniz. Ayrıca, kullanıcıların projelerine yükledikleri kodu incelemelerine olanak tanıyarak onlara yardımcı olabilirsiniz.

    Şu anda bu, uzantınızı herkese açık bir GitHub deposunda kullanıma sunmak anlamına gelir.

  3. firebase ext:dev:upload komutunu kullanarak uzantınızı Uzantı Merkezi'ne yükleyin.

  4. Firebase konsolundaki yayıncı kontrol panelinize gidin, yeni yüklediğiniz uzantıyı bulun ve "Uzantı Merkezi'nde yayınla"yı tıklayın. Bu işlem, inceleme ekibimizden inceleme isteğinde bulunulmasını gerektirir ve birkaç gün sürebilir. Onaylanırsa uzantı, Uzantı Merkezi'nde yayınlanır. Başvurunuz reddedilirse nedenini açıklayan bir mesaj alırsınız. Ardından, bildirilen sorunları giderip incelenmek üzere yeniden gönderebilirsiniz.