Recupera i dati da un'API REST in un'applicazione DOM virtuale Oracle JET

Introduzione

Questa esercitazione descrive come accedere a un servizio REST, integrarlo nell'applicazione DOM virtuale Oracle JavaScript Extension Toolkit (Oracle JET) e associare i dati a una vista elenco nell'interfaccia utente.

Obiettivi

In questa esercitazione verrà descritto come creare le istanze della classe RESTDataProvider. Questa classe rappresenta i dati disponibili dai servizi REST basati su JSON.

Prerequisiti

Task 1: Scarica l'app Starter Virtual DOM

Saltare questo task se si continua a lavorare in un'applicazione creata nel percorso di apprendimento precedente.

  1. Rinominare jet-virtual-dom-app-temp.zip come JET-Virtual-DOM-app.zip. Estrarre il contenuto nella directory JET-Virtual-DOM-app.

  2. Passare alla directory JET-Virtual-DOM-app e ripristinare l'applicazione Oracle JET Virtual DOM.

    npm install
    

    L'applicazione DOM virtuale è pronta per l'uso.

Task 2: Accesso al servizio REST

Fare clic sul collegamento APEX per visualizzare i dati REST per l'endpoint della risorsa Attività.

I dati contengono un elenco di attività con vari attributi.

{
  "items": [
      {
      "id": 1,
      "name": "Baseball",
      "short_desc": "Equipment we carry for baseball players.",
      "image": "css/images/product_images/baseball.jpg"
      },
   . . .
   ],
   "hasMore": false,
   "limit": 25,
   "offset": 0,
   "count": 4,
   "links": [
      {
      "rel": "self",
      "href": "https://apex.oracle.com/pls/apex/oraclejet/lp/activities/"
      },
      . . .
   ]
}

Familiarizzare con i dati e le proprietà restituite dall'endpoint. È necessario comprendere questi dettagli quando si crea un'istanza di RESTDataProvider più avanti in questa esercitazione. Si noti, ad esempio, come l'endpoint restituisce una proprietà items che fa riferimento a una serie di singole attività.

Task 3: Creare un provider di dati per recuperare i dati dell'attività

  1. Passare alla directory JET-Virtual-DOM-app/src/components/ e aprire il file ParentContainer1.tsx in un editor.

  2. All'inizio del file ParentContainer1.tsx, importare il modulo RESTDataProvider ed eliminare o commentare le istruzioni di importazione per il modulo MutableArrayDataProvider e il file store_data.json.

    Importiamo anche l'hook useMemo che utilizzeremo durante la creazione di RESTDataProvider in un secondo momento.

    import { h } from "preact";
    . . .
    // import MutableArrayDataProvider = require("ojs/ojmutablearraydataprovider");
    // import * as storeData from "text!./store_data.json";
    import { RESTDataProvider } from "ojs/ojrestdataprovider";
    import { useState, useMemo } from "preact/hooks";
    . . .
    
  3. Creare una variabile keyattributes e una variabile restServerURLActivities che faccia riferimento all'attributo chiave attività e all'endpoint REST che si passerà all'istanza RESTDataProvider che si creerà nel passo successivo.

    let keyAttributes: string = 'id';
    // REST endpoint that returns Activity data
    const restServerURLActivities: string =
      'https://apex.oracle.com/pls/apex/oraclejet/lp/activities/';
    
  4. Creare una nuova variabile activityDataProvider che faccia riferimento al modulo RESTDataProvider ed eliminare o commentare la variabile activityDataProvider preesistente che fa riferimento al modulo MutableArrayDataProvider.

    Creiamo la nuova variabile activityDataProvider all'interno della funzione ParentContainer1 e la avvolgiamo all'interno di un hook useMemo per garantire che l'istanza del provider di dati venga ricreata solo se i dati nel provider di dati cambiano effettivamente.

    const ParentContainer1 = () => {
    
    const activityDataProvider = useMemo(() => new RESTDataProvider<Activity["id"], Activity>({
       keyAttributes: keyAttributes,
       url: restServerURLActivities,
       transforms: {
          fetchFirst: {
          request: async (options) => {
             const url = new URL(options.url);
             const { size, offset } = options.fetchParameters;
             url.searchParams.set("limit", String(size));
             url.searchParams.set("offset", String(offset));
             return new Request(url.href);
          },
          response: async ({ body }) => {
             const { items, totalSize, hasMore } = body;
             return { data: items, totalSize, hasMore };
          },
          },
       },
     }), [])
    . . .
    

    Nota: la funzione response sopra riportata che estrae dati e altre proprietà dal corpo della risposta dell'endpoint deve restituire un oggetto con una proprietà data. Poiché l'endpoint con cui lavoriamo restituisce una proprietà items, questa proprietà viene assegnata a data nella funzione di risposta.

  5. Salvare il file ParentContainer1.tsx.

    Il file ParentContainer1.tsx deve avere un aspetto simile a quello del file ParentContainer1-a.tsx.txt.

  6. Passare alla directory JET-Virtual-DOM-app/src/components/Activity e aprire il file ActivityContainer.tsx in un editor.

  7. All'inizio del file ActivityContainer.tsx, importare il modulo RESTDataProvider e commentare o eliminare l'istruzione di importazione per il modulo MutableArrayDataProvider.

       import { h, ComponentProps } from "preact";
       . . .
       // import MutableArrayDataProvider = require("ojs/ojmutablearraydataprovider");
       import { RESTDataProvider } from "ojs/ojrestdataprovider";
       . . .
    
    
  8. Nell'alias di tipo Props, modificare la proprietà facoltativa data per fare riferimento al tipo RESTDataProvider anziché al tipo MutableArrayDataProvider<Activity["id"], Activity> preesistente.

       type Props = {
          data?: RESTDataProvider<Activity["id"], Activity>;
          // data?: MutableArrayDataProvider<Activity["id"], Activity>;
       . . .
       };
    
  9. Salvare il file ActivityContainer.tsx.

    Il file ActivityContainer.tsx deve essere simile a ActivityContainer.tsx.txt.

Task 4: Aggiungere un handler errori per gestire un errore durante il recupero dei dati

L'istanza RESTDataProvider fornisce un'opzione di errore che è possibile utilizzare per richiamare una funzione di callback quando un tentativo di recupero dei dati non riesce. Questa funzionalità verrà implementata per lo scenario in cui un tentativo di recupero della lista di attività non riesce.

  1. Nel file ParentContainer1.tsx della directory JET-Virtual-DOM-app/src/components/, importare l'hook useRef da Preact.

    . . .
    import { RESTDataProvider } from "ojs/ojrestdataprovider";
    import { useState, useMemo, useRef } from "preact/hooks";
    . . .
    
  2. Nella variabile activityDataProvider che fa riferimento a RESTDataProvider aggiungere l'opzione error e un riferimento alla funzione di callback che richiama (fetchErrorHandler).

    const ParentContainer1 = () => {
    
       const activityDataProvider = useMemo(() => new RESTDataProvider<Activity["id"], Activity>({
          keyAttributes: keyAttributes,
          url: restServerURLActivities,
          error: fetchErrorHandler,
          transforms: {
          . . .
    
  3. Prima della variabile activityDataProvider, aggiungere il codice per fetchErrorHandler e gli hook (useState e useRef) utilizzati per determinare se il tentativo di recuperare i dati è riuscito.

    . . .
    const ParentContainer1 = () => {
    
    const [fetchStatus, setFetchStatus] = useState(true);
    const fetchError = useRef<string>();
    
    const fetchErrorHandler = (errorDetail: RESTDataProvider.FetchErrorDetail<number, Activity> |
                                            RESTDataProvider.FetchResponseErrorDetail<number, Activity>) => {
       setFetchStatus(false);
       if (errorDetail.hasOwnProperty('response')) {
          fetchError.current = `${(errorDetail as RESTDataProvider.FetchResponseErrorDetail<number, Activity>).response.status}`;
       }
       else {
          fetchError.current = (errorDetail as RESTDataProvider.FetchErrorDetail<number, Activity>).error.message;
       }
    }
    
    const activityDataProvider = new RESTDataProvider<Activity["id"], Activity>({
    . . .
    
  4. Nell'istruzione return alla fine del file ParentContainer1.tsx, aggiungere un controllo che determina se visualizzare la lista di attività o un messaggio nel caso in cui il tentativo di recupero dei dati non sia riuscito.

    . . .
    return (
       <div>
          {fetchStatus ? (
          <div id="parentContainer1" class="oj-flex oj-flex-init">
             <ActivityContainer data={activityDataProvider} onActivityChanged={activityChangedHandler} />
             {showActivityItems() && (<ParentContainer2 activity={selectedActivity} />)}
             {!showActivityItems() && (<h4 class="oj-typography-subheading-sm">Select activity to view items</h4>)}
          </div>) :
          (<p>Sorry that we couldn't get your product information right now. Please contact your system administrator.</p>
          )}
       </div>
    );
    };
    
    export default ParentContainer1;
    
  5. Salvare il file ParentContainer1.tsx.

    Il file ParentContainer1.tsx deve avere un aspetto simile a quello del file ParentContainer1-b.tsx.txt.

Task 5: Creare un provider di dati per recuperare i dati degli elementi

Utilizzare un'altra istanza RESTDataProvider per recuperare un subset dei dati, ovvero la lista di elementi per una determinata attività. A tale scopo, specificare un nuovo URL contenente l'ID attività selezionato.

  1. Passare alla directory JET-Virtual-DOM-app/src/components/ e aprire il file ParentContainer2.tsx in un editor.

  2. All'inizio del file ParentContainer2.tsx, importare il modulo RESTDataProvider ed eliminare o commentare le istruzioni di importazione per il modulo MutableArrayDataProvider e il file store_data.json. Importare anche l'interfaccia TextFilter che verrà utilizzata quando si abilita la funzionalità di filtro nell'istanza RESTDataProvider creata.

    import { h } from "preact";
    . . .
    import { RESTDataProvider } from "ojs/ojrestdataprovider";
    import { TextFilter } from "ojs/ojdataprovider";
    
    // import MutableArrayDataProvider = require("ojs/ojmutablearraydataprovider");
    // import * as storeData from "text!./store_data.json";
    . . .
    
    
  3. Dopo l'alias di tipo Item, creare una variabile baseServiceUrl per fare riferimento all'endpoint REST che verrà passato all'istanza di RESTDataProvider che verrà creata nel passo successivo.

    type Item = {
       . . .
     };
    
    const baseServiceUrl =
      "https://apex.oracle.com/pls/apex/oraclejet/lp/activities/";
    
  4. Creare un'istanza iniziale di RESTDataProvider che verrà passata nei passi successivi agli hook di useState e useEffect Preact.

       const baseServiceUrl = 'https://apex.oracle.com/pls/apex/oraclejet/lp/activities/';
    
       let INIT_DATAPROVIDER = new RESTDataProvider<ActivityItem['id'], ActivityItem>({
       keyAttributes: 'id',
       url: baseServiceUrl,
       transforms: {
          fetchFirst: {
             request: null!,
             response: (): any => {
             return { data: [] };
             },
          },
       },
       });
    
  5. Commentare o eliminare il codice preesistente che ha creato una variabile per leggere i dati dal file store_data.json e che ha creato un'istanza iniziale di MutableArrayDataProvider.

       // const activityData = JSON.parse(storeData);
       // let activityItemsArray = activityData[0].items;
    
       // // Create data provider instance for the array of activity items for the selected activity
       // const INIT_DATAPROVIDER = new MutableArrayDataProvider<ActivityItem["id"], ActivityItem>(activityItemsArray, {
       //   keyAttributes: "id",
       // })
    
  6. Nella funzione ParentContainer2 sostituire l'hook useEffect esistente che gestisce l'istanza di MutableArrayDataProvider con una nuova definizione che crea un RESTDataProvider per gli elementi attività che corrispondono all'ID attività selezionato. Questa nuova definizione include anche un filtro di testo per filtrare il campo name dell'elemento attività.

    const ParentContainer2 = (props: Props) => {
    . . .
    useEffect(() => {
       setactivityItemDP(
          new RESTDataProvider<ActivityItem["id"], ActivityItem>({
          keyAttributes: "id",
          capabilities: {
             filter: {
                textFilter: true,
             },
          },
          url: baseServiceUrl + "/" + props.activity?.id + "/items/",
          textFilterAttributes: ["name"],
          transforms: {
             fetchFirst: {
                request: async (options) => {
                const url = new URL(options.url);
                const { size, offset } = options.fetchParameters;
                url.searchParams.set("limit", String(size));
                url.searchParams.set("offset", String(offset));
                const filterCriterion = options.fetchParameters
                   .filterCriterion as TextFilter<Item>;
                const { textFilterAttributes } = options.fetchOptions;
                if (
                   filterCriterion &&
                   filterCriterion.text &&
                   textFilterAttributes
                ) {
                   const { text } = filterCriterion;
                   textFilterAttributes.forEach((attribute) => {
                      url.searchParams.set(attribute, text);
                   });
                }
    
                return new Request(url.href);
                },
                response: async ({ body }) => {
                const { items, totalSize, hasMore } = body;
                return { data: items, totalSize, hasMore };
                },
             },
          },
          })
       );
    }, [props.activity]);
    
    return (
    . . .
    
  7. Salvare il file ParentContainer2.tsx.

    Il file ParentContainer2.tsx deve essere simile al file ParentContainer2.tsx.txt.

  8. Passare alla directory JET-Virtual-DOM-app/src/components/ActivityItem e aprire il file ActivityItemContainer.tsx in un editor.

  9. All'inizio del file ActivityItemContainer.tsx, importare il modulo RESTDataProvider e commentare o eliminare l'istruzione di importazione per il modulo MutableArrayDataProvider.

    import { h, ComponentProps } from "preact";
    . . .
    // import MutableArrayDataProvider = require("ojs/ojmutablearraydataprovider");
    import { RESTDataProvider } from "ojs/ojrestdataprovider";
    . . .
    
  10. Nell'alias di tipo Props, modificare la proprietà data in modo che faccia riferimento al tipo RESTDataProvider anziché al tipo MutableArrayDataProvider<Activity["id"], Activity> preesistente.

    type Props = {
      // data?: MutableArrayDataProvider<ActivityItem["id"], ActivityItem>;
      data?: RESTDataProvider<ActivityItem['id'], ActivityItem>;
      selectedActivity: Item | null;
      onItemChanged: (item: Item) => void;
    };
    
  11. Salvare il file ActivityItemContainer.tsx.

    Il file ActivityItemContainer.tsx deve essere simile a ActivityItemContainer.tsx.txt.

Task 6: Test dell'applicazione DOM virtuale

  1. Nella finestra del terminale, passare alla directory JET-Virtual-DOM-app ed eseguire l'applicazione DOM virtuale.

    npx ojet serve
    
  2. Nella finestra del browser, visualizza le modifiche dinamiche nella tua applicazione DOM virtuale.

    Schermata Record recuperati

  3. Chiudere la finestra o la scheda del browser che visualizza l'applicazione DOM virtuale in esecuzione.

  4. Nella finestra del terminale, premere Ctrl+C e, se richiesto, immettere y per uscire dal job batch degli strumenti Oracle JET.

  5. Nella finestra del terminale, eseguire l'applicazione DOM virtuale utilizzando i seguenti argomenti aggiuntivi della riga di comando.

    npx ojet serve --server-port=8144 --livereload-port=8145
    

    In questa occasione, l'applicazione DOM virtuale visualizza il seguente messaggio perché il servizio REST di cui si è fidato per accedere accetta solo le richieste sulla porta del server che il comando ojet serve utilizza per impostazione predefinita (8000), pertanto il tentativo da parte di RESTDataProvider di recuperare dal servizio REST non è riuscito.

    Sorry that we couldn't get your product information right now. Please contact your system administrator.
    

Passo successivo

Passare all'esercitazione successiva in questo modulo.

Questa esercitazione fa parte del modulo Operazioni CRUD mediante un servizio REST.

Puoi tornare alla pagina principale del percorso di apprendimento DOM virtuale per accedere a tutti i moduli sulla creazione di app DOM virtuali.

Altre risorse di apprendimento

Esplora altri laboratori su docs.oracle.com/learn o accedi a più contenuti di formazione gratuiti sul canale YouTube di Oracle Learning. Inoltre, visitare education.oracle.com/learning-explorer per diventare Oracle Learning Explorer.

Per la documentazione del prodotto, visitare Oracle Help Center.