Extrair dados de uma API REST em um aplicativo Oracle JET DOM virtual

Introdução

Este tutorial mostra como acessar um serviço REST, integrá-lo ao seu aplicativo DOM virtual Oracle JavaScript Extension Toolkit (Oracle JET) e vincular dados a uma exibição em lista na interface do usuário.

Objetivos

Neste tutorial, você aprenderá a criar instâncias da classe RESTDataProvider. Essa classe representa dados disponíveis dos serviços REST baseados em JSON.

Pré-requisitos

Tarefa 1: Fazer Download do Aplicativo Starter Virtual DOM

Ignore essa tarefa se você continuar trabalhando em um aplicativo criado na programação de estudo anterior.

  1. Renomeie jet-virtual-dom-app-temp.zip como JET-Virtual-DOM-app.zip. Extraia o conteúdo para o diretório JET-Virtual-DOM-app.

  2. Navegue até o diretório JET-Virtual-DOM-app e restaure o aplicativo DOM virtual do Oracle JET.

    npm install
    

    O aplicativo DOM virtual está pronto para uso.

Tarefa 2: Acessar o Serviço REST

Clique no link Apex para exibir os dados REST do ponto final do recurso Atividades.

Os dados contêm uma lista de atividades com vários atributos.

{
  "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/"
      },
      . . .
   ]
}

Familiarize-se com os dados e as propriedades que o ponto final retorna. Você precisará entender esses detalhes ao criar uma instância do RESTDataProvider posteriormente neste tutorial. Observe, por exemplo, como o ponto final retorna uma propriedade items que faz referência a uma série de atividades individuais.

Tarefa 3: Criar um Provedor de Dados para Extrair Dados da Atividade

  1. Navegue até o diretório JET-Virtual-DOM-app/src/components/ e abra o arquivo ParentContainer1.tsx em um editor.

  2. No início do arquivo ParentContainer1.tsx, importe o módulo RESTDataProvider e exclua ou comente as instruções de importação do módulo MutableArrayDataProvider e do arquivo store_data.json.

    Também importamos o gancho useMemo que usaremos ao criar o RESTDataProvider posteriormente.

    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. Crie uma variável keyattributes e uma variável restServerURLActivities que façam referência ao atributo de chave da atividade e ao ponto final REST que você passará para a instância RESTDataProvider que você criará na próxima etapa.

    let keyAttributes: string = 'id';
    // REST endpoint that returns Activity data
    const restServerURLActivities: string =
      'https://apex.oracle.com/pls/apex/oraclejet/lp/activities/';
    
  4. Crie uma nova variável activityDataProvider que faça referência ao módulo RESTDataProvider e exclua ou comente a variável activityDataProvider preexistente que fez referência ao módulo MutableArrayDataProvider.

    Criamos a nova variável activityDataProvider na função ParentContainer1 e a encapsulamos em um gancho useMemo para garantir que a instância do provedor de dados seja recriada somente se os dados no provedor de dados realmente mudarem.

    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 };
          },
          },
       },
     }), [])
    . . .
    

    Observação: A função response acima que extrai dados e outras propriedades do corpo de resposta do ponto final deve retornar um objeto com uma propriedade data. Como o ponto final com o qual trabalhamos retorna uma propriedade items, designamos essa última propriedade a data na função de resposta.

  5. Salve o arquivo ParentContainer1.tsx.

    Seu arquivo ParentContainer1.tsx deve ter aparência semelhante a ParentContainer1-a.tsx.txt.

  6. Navegue até o diretório JET-Virtual-DOM-app/src/components/Activity e abra o arquivo ActivityContainer.tsx em um editor.

  7. No início do arquivo ActivityContainer.tsx, importe o módulo RESTDataProvider e comente ou exclua a instrução de importação do módulo MutableArrayDataProvider.

       import { h, ComponentProps } from "preact";
       . . .
       // import MutableArrayDataProvider = require("ojs/ojmutablearraydataprovider");
       import { RESTDataProvider } from "ojs/ojrestdataprovider";
       . . .
    
    
  8. No alias do tipo Props, modifique a propriedade data opcional para fazer referência ao tipo RESTDataProvider em vez do tipo pré-existente MutableArrayDataProvider<Activity["id"], Activity>.

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

    Seu arquivo ActivityContainer.tsx deve ser semelhante ao ActivityContainer.tsx.txt.

Tarefa 4: Adicionar um Handler de Erro para Gerenciar uma Falha ao Extrair Dados

A instância RESTDataProvider fornece uma opção de erro que você pode usar para chamar uma função de callback quando uma tentativa de extrair dados falhar. Você implementará esse recurso para o cenário em que uma tentativa de extrair a lista de atividades falhar.

  1. No arquivo ParentContainer1.tsx do diretório JET-Virtual-DOM-app/src/components/, importe o gancho useRef do Preact.

    . . .
    import { RESTDataProvider } from "ojs/ojrestdataprovider";
    import { useState, useMemo, useRef } from "preact/hooks";
    . . .
    
  2. Na variável activityDataProvider que faz referência a RESTDataProvider, adicione a opção error e uma referência à função de callback que ela chama (fetchErrorHandler).

    const ParentContainer1 = () => {
    
       const activityDataProvider = useMemo(() => new RESTDataProvider<Activity["id"], Activity>({
          keyAttributes: keyAttributes,
          url: restServerURLActivities,
          error: fetchErrorHandler,
          transforms: {
          . . .
    
  3. Antes da variável activityDataProvider, adicione o código para fetchErrorHandler e os ganchos (useState e useRef) que usamos para determinar se a tentativa de extrair dados foi bem-sucedida.

    . . .
    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. Na instrução de retorno no final do arquivo ParentContainer1.tsx, adicione uma verificação que determine se você exibe a lista de atividades ou uma mensagem no caso de falha na tentativa de extrair dados.

    . . .
    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. Salve o arquivo ParentContainer1.tsx.

    Seu arquivo ParentContainer1.tsx deve ter aparência semelhante a ParentContainer1-b.tsx.txt.

Tarefa 5: Criar um Provedor de Dados para Extrair Dados do Item

Use outra instância do RESTDataProvider para extrair um subconjunto dos dados, a lista de itens de uma atividade específica. Para isso, forneça um novo URL que contenha o ID da atividade selecionada.

  1. Navegue até o diretório JET-Virtual-DOM-app/src/components/ e abra o arquivo ParentContainer2.tsx em um editor.

  2. No início do arquivo ParentContainer2.tsx, importe o módulo RESTDataProvider e exclua ou comente as instruções de importação do módulo MutableArrayDataProvider e do arquivo store_data.json. Também importe a interface TextFilter que usaremos quando ativarmos o recurso de filtragem na instância RESTDataProvider que criamos.

    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. Após o alias do tipo Item, crie uma variável baseServiceUrl para fazer referência ao ponto final REST que você passará para a instância do RESTDataProvider que você criará na próxima etapa.

    type Item = {
       . . .
     };
    
    const baseServiceUrl =
      "https://apex.oracle.com/pls/apex/oraclejet/lp/activities/";
    
  4. Crie uma instância inicial do RESTDataProvider que você passará nas etapas subsequentes para os ganchos 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. Comente ou exclua o código pré-existente que criou uma variável para ler dados do arquivo store_data.json e que criou uma instância inicial do 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. Na função ParentContainer2, substitua o gancho useEffect existente que gerencia a instância de MutableArrayDataProvider por uma nova definição que crie um RESTDataProvider para os itens de atividade que correspondem ao ID da atividade selecionada. Essa nova definição também inclui um filtro de texto para filtrar o campo name do item de atividade.

    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. Salve o arquivo ParentContainer2.tsx.

    Seu arquivo ParentContainer2.tsx deve ser semelhante ao ParentContainer2.tsx.txt.

  8. Navegue até o diretório JET-Virtual-DOM-app/src/components/ActivityItem e abra o arquivo ActivityItemContainer.tsx em um editor.

  9. No início do arquivo ActivityItemContainer.tsx, importe o módulo RESTDataProvider e comente ou exclua a instrução de importação do módulo MutableArrayDataProvider.

    import { h, ComponentProps } from "preact";
    . . .
    // import MutableArrayDataProvider = require("ojs/ojmutablearraydataprovider");
    import { RESTDataProvider } from "ojs/ojrestdataprovider";
    . . .
    
  10. No alias do tipo Props, modifique a propriedade data para fazer referência ao tipo RESTDataProvider em vez do tipo pré-existente MutableArrayDataProvider<Activity["id"], Activity>.

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

    Seu arquivo ActivityItemContainer.tsx deve ser semelhante ao ActivityItemContainer.tsx.txt.

Tarefa 6: Testar o Aplicativo DOM Virtual

  1. Na janela do terminal, altere para o diretório JET-Virtual-DOM-app e execute o aplicativo DOM virtual.

    npx ojet serve
    
  2. Na janela do navegador, exiba as alterações dinâmicas no seu aplicativo DOM virtual.

    Tela Registros Extraídos

  3. Feche a janela ou guia do navegador que exibe seu aplicativo DOM virtual em execução.

  4. Na janela do terminal, pressione Ctrl+C e, se solicitado, digite y para sair da tarefa em batch de ferramentas do Oracle JET.

  5. Na janela do terminal, execute o aplicativo DOM virtual usando os seguintes argumentos adicionais de linha de comando.

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

    Nesta ocasião, o aplicativo DOM virtual exibe a seguinte mensagem porque o serviço REST que ele usa para acessar aceita apenas solicitações na porta do servidor que o comando ojet serve usa por padrão (8000), de modo que a tentativa do RESTDataProvider de extrair do serviço REST falhou.

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

Próxima Etapa

Prossiga para o próximo tutorial neste módulo.

Este tutorial faz parte do módulo Operações CRUD Usando um Serviço REST.

Você pode retornar à página principal da programação de estudo do DOM virtual para acessar todos os módulos na criação de aplicativos DOM virtuais.

Mais Recursos de Aprendizado

Explore outros laboratórios em docs.oracle.com/learn ou acesse mais conteúdo de aprendizado gratuito no canal do Oracle Learning YouTube. Além disso, acesse education.oracle.com/learning-explorer para se tornar um Oracle Learning Explorer.

Para obter a documentação do produto, visite o Oracle Help Center.