Adobe Commerce


Hands-on Adobe Firefly


Author Photo
Alex Lyzun
Lead Developer Adobe Commerce

Hands-on Adobe Firefly on Adobe I/O

Project Firefly ist ein relativ neues Framework, das Mitte 2020 von Adobe eingeführt wurde und sich derzeit noch in der Beta-Phase befindet (Stand: 05.02.2021). Ich habe schon früh von dem Projekt gehört, hatte aber erst kürzlich die Gelegenheit, mich damit zu beschäftigen.

Nachdem ich ein paar Tage mit dem Firefly herumgespielt hatte, wurde mir klar, dass es wirklich einen eigenen Artikel verdient hat, und hier ist er nun.

Ich möchte betonen, dass alles, was ich hier schreibe, auf meinen eigenen Erfahrungen beruht. Und ich möchte diese Erfahrungen mit Leuten teilen, die gerade mit dem Firefly-Projekt beginnen und es besser kennenlernen wollen.


Project Firefly

Was ist das Firefly-Projekt? Wie auf der Homepage von Project Firefly beschrieben - "Project Firefly is a complete framework for building and deploying custom web applications in minutes on our serverless platform".

Die Hauptidee ist es, Entwicklern und Integratoren eine Plattform zur Verfügung zu stellen, mit der sie ihre Anwendungen erstellen und bereitstellen können, ohne sich um das Hosting oder die Hardware für die Anwendungen kümmern zu müssen. Das gesamte System bietet Ihnen eine Umgebung, in der Sie Ihre Anwendungen sicher entwickeln, bereitstellen, testen und freigeben können. Es stellt eine breite Palette von Tools für die Erstellung von JS-basierten Microservices und UI-Schnittstellen für diese bereit und ermöglicht deren sichere Nutzung und Integration in Ihre Architektur.

Für mich als Adobe Commerce / Magento Open Source Architekt war dieses Projekt aus der Perspektive der Microservices sehr interessant. Da Magento ein riesiges E-Commerce-System ist, das immer noch als Monolith präsentiert wird, sind Fragen der Skalierbarkeit und Wartbarkeit von entscheidender Bedeutung, insbesondere wenn es um die Integration von Magento in komplexe Architekturen mit Millionen von Entitäten und einer großen Anzahl anderer Dienste geht.

Ich sehe das Firefly-Projekt als eine Möglichkeit, die Last des Magento-Monolithen zu reduzieren, indem verschiedene Prozesse und Berechnungen an die Firefly-Infrastruktur und -Dienste delegiert werden.


Wie Sie Zugang zu Firefly erhalten

Wie bereits erwähnt, befindet sich Firefly derzeit in der Betaphase und Sie können sich auf der Hauptseite des Projekts für eine Vorschau anmelden:   Creating a custom native Adobe Cloud app.

Wenn Sie ein einzelner Entwickler sind, müssen Sie leider eine Organisations-ID angeben, was bedeutet, dass Adobe nur Organisationen Zugang gewährt.

Nachdem Sie ein Antragsformular eingereicht haben, wird Ihnen der Zugang gewährt.


Erste Schritte

Ich werde hier nicht zu sehr ins Detail gehen. Sie können dieser Dokumentation folgen, um ein neues Projekt zu erstellen:

Project Firefly Docs 

Ich möchte ein paar Punkte anmerken:

  • Ich musste Adobe AIO-CLI installieren.
  • Wenn Sie mehr Details suchen, können Sie den Quellcode auf Github finden: https://github.com/adobe/aio-cli  
  • Sie können auch den Adobe-Namensraum durchsuchen und andere interessante Projekte finden. Wenn Sie fertig sind, können Sie sich mit dem Befehl "aio login" bei Adobe Infrastructure anmelden.
  • Nachdem Sie "aio app run -local" ausgeführt haben, erhalten Sie Links zum Öffnen Ihrer gebootstrappten Anwendung im Browser
Adobe AIO CLI running on your terminal

Von diesem Moment an läuft Ihre Anwendung und kann getestet werden. Beachten Sie, dass die Anwendung standardmäßig mit LOG_LEVEL: debug läuft (dies kann später in manifest.yml für jede Laufzeitaktion separat geändert werden). Alle Protokolle, die Ihre Anwendung erzeugt, können direkt in der Konsolenausgabe angezeigt werden. Beachten Sie jedoch, dass die Protokollierung nach der Ausführung einer Aktion einige Zeit dauern kann.

Wenn Sie etwas im Code ändern, müssen Sie die Anwendung nicht neu starten, nach ein paar Sekunden sind die Änderungen verfügbar und Sie können erneut testen.

Ich gehe davon aus, dass Sie die grundlegenden Anweisungen befolgt haben und die Standardanwendung zum Laufen bringen konnten.


Let's play around

We have defined 2 milestones for our test task:

  1. Create the ability to enter the header and body of an API request into Magento and publish products via the POST /products endpoint.
  2. Create a headless service that can import files from external CSV files into Magento

Part 1: UI for API Requests

First, we are adding a new runtime action, which will execute the operations we need

In manifest.yml add:

push-product:
function: actions/push-product/index.js
 web: 'yes'
 runtime: 'nodejs:12'
 inputs:
  LOG_LEVEL: debug
  apiKey: $SERVICE_API_KEY
 annotations:
   require-adobe-auth: false
   final: true

Then in the /actions folder create a new index.js file where we can define our actions:

const Papa = require('papaparse')
 const fetch = require('node-fetch')
 const { Core, Events } = require('@adobe/aio-sdk')
 const uuid = require('uuid')
 const cloudEventV1 = require('cloudevents-sdk/v1')
 const { errorResponse, getBearerToken, stringParameters, checkMissingRequestInputs } = require('../utils')

 // main function that will be executed by Adobe I/O Runtime 
 async function main (params) {

   // create a Logger
   const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })

   try {
    // 'info' is the default level if not set
    logger.info('Calling the main action')

    const apiEndpoint = 'https://URL/rest/V1/products'

    const res = await fetch(apiEndpoint, {
        method: 'POST',
        body: JSON.stringify(params.import_data),
        headers: {
            "Authorization": params.__ow_headers['authorization'],
            "Content-Type": params.__ow_headers['content-type'],
        }
    })

    if (!res.ok) {
        logger.info((res))
        throw new Error('request to ' + apiEndpoint + ' failed with status code ' + res.status)
    }
    const content = await res.json()
    const response = {
        statusCode: 200,
        body: content
    }
    logger.info(stringParameters(response))
    return response

   } catch (error) {
     // log any server errors
     logger.error(error)
     // return with 500
     return errorResponse(500, 'server error', logger)
   }
 }

 exports.main = main

In this code sample, parameters that you specified through your application's form are passed to Magento through the REST API. The response to this execution is returned to the user.

Restart your application and you will see a new action in your front-end UI. Now, if you select the "push-product" action and add the headers and body required by Magento REST API to call POST /products, you can successfully publish a new product to the Magento backend.

Adding a new product in Adobe Commerce using project firefly in Adobe I/O

Part 2: Create CSV Importer / Crons

For the second part we have thought about regular import of products into Magento. As a use case - the customer updates a CSV file with new products every day, and your service needs to fetch the file, parse it and publish it to Magento.

Example of a file with product entries:

SKU name attribute_set_id price status visibility type_id
test-product-1 Firefly Test Product 1 4 100 1 4 simple
test-product-2 Firefly Test Product 2 4 999 1 4 simple
... ... ... ... ... ... ...

First of all, in manifest.xml for your action, please remove the "web: 'yes'" flag or set it to "no".

Second, we need to configure the alert feed that triggers our runtime action once a day (we did it once a minute for testing).

To do this, in your manifest.xml add sections with triggers and with rules.

triggers:
    everyMin:
    feed: /whisk.system/alarms/interval
    inputs: 
    minutes: 1
rules:
    everyMinRule:
    trigger: everyMin
    action: generic

Triggers define intervals for the execution of your action. Rules define the mapping between trigger and action.

After making changes, you need to deploy your application using aio app deploy and use the aio rt activation list command to check if your action has been invoked.

Checking invoked actions in the aio rt activation list

So, as you can see, the task implementation doesn't look complex, and Firefly also provides ways to implement it quite quickly.

Full action code (don't forget to install npm install papaparse for CSV parsing).

In short, actions are: 

  • Downloading a CSV file from an external source
  • Parsing the file and reading the contents
  • Convert content into JSON compatible Magento Rest API/products request.
  • Executing the Magento API call to the /products endpoint.
  • Read response

const Papa = require('papaparse')
 const fetch = require('node-fetch')
 const { Core, Events } = require('@adobe/aio-sdk')
 const uuid = require('uuid')
 const cloudEventV1 = require('cloudevents-sdk/v1')
 const { errorResponse, getBearerToken, stringParameters, checkMissingRequestInputs } = require('../utils')

function csvToJson(csv) {
  const logger = Core.Logger('main', { level: 'debug' })

  logger.debug(JSON.stringify(csv));
  const header = csv[0];

  const out = csv.map((el, i) => {
    if (i === 0)
      return {};
    const obj = {};
    el.forEach((item, index) => {
      obj[header[index].trim()] = item.trim();
    })

    const newObj = {};
    newObj.product = obj;
    return newObj;
  });

  logger.debug(JSON.stringify(out));

  return out;
}

 // main function that will be executed by Adobe I/O Runtime 
 async function main (params) {
   // create a Logger
   const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })

   try {
    // 'info' is the default level if not set
    logger.info('Calling the main action')

    const csv = await fetch("https://URL/media/firefly.csv")
        .then(resp => resp.text())
        .then(result => {
          const res = Papa.parse(result);
          return csvToJson(res.data);
        })

    // replace this with tddhe api you want to access
    const apiEndpoint = 'https://URL/rest/V1/products'

    const content = [];
    const out = Promise.all(csv.map(async (el, i) => {      
        if (i === 0)
            return;
        const res = await fetch(apiEndpoint, {
            method: 'POST',
            body: JSON.stringify(el),
            headers: {
                "Authorization": “Bearer 123123123",
                "Content-Type": “application/json",
            }
        })         

        if (!res.ok) {
            logger.info((res))
            throw new Error('request to ' + apiEndpoint + ' failed with status code ' + res.status)
        }
        content.push(await res.json());        
    }));        

    const response = {
        statusCode: 200,
        body: content
    }
    logger.info(stringParameters(response))
    return response

   } catch (error) {
     // log any server errors
     logger.error(error)
     // return with 500
     return errorResponse(500, 'server error', logger)
   }
 }
 exports.main = main


Debugging with VSCode

Debugging of Firefly application is quite easy.

Add the following code into ".vscode/launch.json" in case you are adding a new runtime action.

{
"type": "pwa-node",
 "name": "Action:csvimportmagento-0.0.1/push-product",
 "request": "launch",
 "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/wskdebug",
 "envFile": "${workspaceFolder}/dist/.env.local",
 "timeout": 30000,
 "killBehavior": "polite",
 "localRoot": "${workspaceFolder}",
 "remoteRoot": "/code",
 "outputCapture": "std",
 "attachSimplePort": 0,
 "runtimeArgs": [
  "csvimportmagento-0.0.1/push-product",
   "${workspaceFolder}/actions/push-product/index.js",
   "-v",
   "—disable-concurrency",
   "—kind",
   "nodejs:12"
 ]
},
...
"compounds": [
    {
      "name": "Actions",
      "configurations": [
        ......
        "Action:csvimportmagento-0.0.1/push-product"
      ]
    },
    {
      "name": "WebAndActions",
      "configurations": [
        ......
        "Action:csvimportmagento-0.0.1/push-product"
      ]
    }
  ]

Then just set breakpoints for the required elements, choose the actions you want to debug, and click start.

Debugging Project Firefly

Conclusion

For me, Project Firefly is something I have been waiting for a long time. Since I started working on complex and heavy systems, I came to the conclusion that there are no other ways to delegate part of the Magento system to other services. So Firefly is exactly what I was looking for.

The topics and examples I covered in this article are just a small part of everything Firefly can do for microservices environments.

And it only took me a day to fall in love with the software.

I'm looking forward to working with React Spectrum and UI frameworks, Journaling API, CI/CD in Firefly, working with Adobe Events, and much more.


Related Articles