npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

navidev-abap-gw-api

v0.1.6

Published

API para la extracción de datos de servicios SAP GW

Readme

Objetivo

El objetivo es disponer de una API que permita obtener información de los servicios de gateway de SAP, con lo cual, pueda ser utilizado en otros proyectos fuera del mundo.

Que información se quiere sacar, pues de dos sitios: Metadata y Anotaciones. Del metadata sacaremos información básico de las entidades, campos y relaciones. Y de las anotaciones sacaremos más la info para la parte de UI en Fiori.

Para que quiero tener esta API. Pues para tener a futuro una herramienta que permite generar aplicaciones en React como si fueran Fiori Elements. Aunque no consiguiré que tengan la misma funcionalidad, pero poco a poco.

Instalación

Desde el terminal solo tenemos que instalarlo con nuestro gestor de paquetes favorito:

pnpm install navidev-abap-gw-api

o

npm install navidev-gw-api

API

Busqueda de servicios

Clase: ServiceSearch

Método: searchService

Permite buscar los servicios por nombre, internamente se busca siempre por patron . Los servicios que se devuelven son los mismos que se ven en VS Code cuando se hace una nueva aplicación y seleccionamos un sistema de SAP, se devolverán tanto los servicios odata V2 como V4.

Los parámetros de entrada son:

  • Nombre del servicio. Es un campo opcional e internamente se busca por patrón.

Ejemplo de llamada:

let serviceSearch = new ServiceSearch({
  client: "001",
  language: "EN",
  password: "Password",
  username: "DEVELOPER",
  urlBase: "http://vhcala4hci:50000",
});

serviceSearch.searchService("ZUI").then((response) => {
  if (response.isSuccess) {
    let values = response.getValue() as ServicesOData;
    console.log(values);
  } else {
    let valuesError = response.getErrorValue();
    console.log(valuesError);
  }
});

MetadaInfo

Clase: Metadata

Método: getMetadataInfo

Obtiene la información de entidades y campos de un servicio. Es como llamar al servicio con $metadata al final. Pero a diferencia del metadata estándar, aquí se devuelve información como ayudas para búsqueda o anotaciones de fiori. Este método devuelve la información del servicio ya sea oData V2 o V4 normalizada en una misma estructura de datos, ya que la estructura del metadata estándar depende de la versión OData del servicio.

En el apartado de anotaciones no devuelve toda la información que tiene SAP para Fiori devuelve las básicas y se irán añadiendo a medida que se necesiten.

Los parámetros de entrada son:

  • Nombre del servicio -> Puede ser de tipo Odata V2 o OData V4
  • Opciones en la obtención de los datos:
    • ignoreValueHelp -> No procesa las ayudas para búsqueda. Ya sean por anotación o info semántica (moneda/unidad de medida).
    • ignoreFields -> No procesa los campos.
    • ignoreAnnotVocab -> No procesa las anotaciones del vocabulario de Fiori.

Ejemplo de llamada:

let metadata = new Metadata({
  client: "001",
  language: "EN",
  password: "Password",
  username: "DEVELOPER",
  urlBase: "http://vhcala4hci:50000",
});

metadata.getMetadataInfo("ZUI_BOOKING_O2").then((response) => {
  if (response.isSuccess) {
    let values = response.getValue();
    console.log(values);
  } else {
    let valuesError = response.getErrorValue();
    console.log(valuesError);
  }
});

Binding info

Clase: Metadata

Método: getBindingInfo

Obtiene la información de como llamar al servicio. Es decir, devuelve el path para poder llamar al servicio. Con ese path y la URL del sistema de SAP se construye la url para hacer las llamadas.

Ejemplo de llamada:

let metadata = new Metadata({
  client: "001",
  language: "EN",
  password: "Password",
  username: "DEVELOPER",
  urlBase: "http://vhcala4hci:50000",
});

metadata.getBindingInfo("ZUI_FIR_T003_O4").then((response) => {
  if (response.isSuccess) {
    let values = response.getValue();
    console.log(values);
  } else {
    let valuesError = response.getErrorValue();
    console.log(valuesError);
  }
});

Operaciones CRUD

Las operaciones CRUD son los métodos para consultar, crear, actualizar y borrar datos. Las operación CRUD se realizan a través de la clase CrudOperations.

Con lo cual lo primero que hay que hacer es instanciar de la siguiente manera:

 let crudOperations = new CrudOperations({
  client: "001",
  language: "EN",
  password: "password",
  username: "DEVELOPER",
  urlBase: "http://vhcala4hci:50000",
});

A continuación hay que conectarse al servicio de la siguiente manera:

 crudOperations.connect("ZUI_BOOKING_O2").then((response) => {
  if (response.isSuccess) {

    // METODO A EJECUTAR

  } else {
    let valuesError = response.getErrorValue();
    console.log(valuesError);
  }
});

Consultas

Métodos para la lectura de datos.

QUERY

El query devuelve un array de valores en base a los fitros introducidos.

query<types>(entidad,opciones)

En types se especifica un tipo de datos array con los campos que devolverá el servicio.

En entidad nombre de la entidad del servicio a la cual se quiere hacer la consulta.

En opciones son los parámetros de la consulta. Las opciones son las siguientes, todas los campos son opcionales:

  • select -> Campos que se quieren recuperar de la consulta
  • filters -> Filtros de la consulta. Se usará para hacer la llama de tipo query
  • urlParameters -> Parámetros que se quieran pasar a la URL
  • top -> Numero de registros a recuperar
  • skip -> Junto al parámetro top se usa para hacer paginaciones
  • sort -> Campos para realizar la ordenacióm

Ejemplo de una llamada query:

type Booking = {
  TravelID: string;
  BookingID: string;
  BookingDate: Date;
  CustomerID: string;
  CarrierID: string;
};
type Bookings = Booking[];

 crudOperations.connect("ZUI_BOOKING_O2").then((response) => {
  if (response.isSuccess) {

       crudOperations
      .query<Bookings>("booking", {
        filters: [
          { field: "TravelID", value1: "1" },
          { field: "TravelID", value1: "2" },
          {
            field: "BookingID",
            value1: "1",
            value2: "10",
            option: FilterOptions.between,
          },
        ],
        top: 2,
      })
      .then((responseQuery) => {
        if (responseQuery.isSuccess) {
          let values = responseQuery.getValue();
          console.log(values);
        } else {
          let valuesError = responseQuery.getErrorValue();
          console.log(valuesError);
        }
      });
  } else {
    let valuesError = response.getErrorValue();
    console.log(valuesError);
  }
});

READ

El read devuelve un registro con el registro encontrado en base a la claves introducidas.

query<types>(entidad,campos clave)

En types se especifica un tipo de datos array con los campos que devolverá el servicio.

En entidad nombre de la entidad del servicio a la cual se quiere hacer la consulta.

En campos clave JSON con los campos clave del registro y sus valores.

Ejemplo de una llamada READ:

type Booking = {
  TravelID: string;
  BookingID: string;
  BookingDate: Date;
  CustomerID: string;
  CarrierID: string;
};

crudOperations.connect("ZUI_DMO_BOOKING_O4").then((response) => {
  if (response.isSuccess) {
    crudOperations
      .read<Booking>("booking", { TravelID: "1", BookingID: "1" })
      .then((responseQuery) => {
        if (responseQuery.isSuccess) {
          let values = responseQuery.getValue();
          console.log(values);
        } else {
          let valuesError = responseQuery.getErrorValue();
          console.log(valuesError);
        }
      });
  } else {
    let valuesError = response.getErrorValue();
    console.log(valuesError);
  }
});

Actualizaciones

Las actualizaciones son aquellos método que permitir añadir, actualizar o borrar registros

POST, oData V2

Método para añadir registros. A este método se le pasa la entidad, un JSON con los datos y los tipos de datos de los datos de actualización y respuesta.

Ejemplo de llamada:

type Booking = {
  TravelID: string;
  BookingID: string;
  BookingDate: Date;
  CustomerID: string;
  CarrierID: string;
};

type BookingPost = {
  TravelID: string;
  BookingID: string;
  BookingDate: Date;
  CustomerID: string;
  CarrierID: string;
  FlightPrice: number;
  CurrencyCode: string;
};

crudOperations.connect("ZUI_BOOKING_O2").then((response) => {
  if (response.isFailure) {
    let valuesError = response.getErrorValue();
    console.log(valuesError);
    return;
  }

  let booking: BookingPost = {
    TravelID: "1",
    BookingID: "1",
    BookingDate: new Date(),
    CustomerID: "1",
    CarrierID: "1",
    FlightPrice: 100.2,
    CurrencyCode: "EUR",
  };

  crudOperations
    .post<Booking, BookingPost>("booking", booking)
    .then((responsePost) => {
      if (responsePost.isFailure) {
        let valuesError = responsePost.getErrorValue();
        console.log(valuesError);
        return;
      }
      let values = responsePost.getValue();
      console.log(values);
    });
});

POST, oData V2

Con el OData V4 los datos no se graban directamente en la base de datos, sino, que primero se graban en la tabla de borrador. Luego hay que pasar de la tabla borrador a la tabla definitiva. Para simplificar estos pasos, se han puesto opciones en el método POST para simplificarlos que serán mostrados en los siguiente ejemplos.

Importante recalcar que debido al borrador sap necesita el parámetro oDataEtag que se usa para actualizar borrador o activar un borrador. Para simplificar las llamada este campo se determina internamente evitando tenerlo que pasarlo en cada momento.

En los ejemplo se usará este tipo de datos:

type BookingPost = {
  TravelID: string
  BookingID: string;
  BookingDate: Date;
  CustomerID: string;
  CarrierID: string;
  FlightPrice: number;
  CurrencyCode: string;
};

Cada llamado al método POST se engloba en esta llamada:

crudOperations.connect("ZUI_DB_BOOKING_O4").then((response) => {
  if (response.isFailure) {
    let valuesError = response.getErrorValue();
    console.log(valuesError);
    return;
  }

// EJEMPLOS POST

  });
Inserción

La inserción más simple es la que se le hace un POST pasandole unos valores. Esta llamada simple siempre generárá un borrador. Tenga, o no, tenga registro existente.


  let booking: BookingPost = {
    TravelID: "1",
    BookingID: "1",
    BookingDate: new Date(),
    CustomerID: "1",
    CarrierID: "1",
    FlightPrice: 20.22,
    CurrencyCode: "EUR",
  };

crudOperations
    .post<Booking, BookingPost>("BOOKING", booking)
    .then((responsePost) => {
      if (responsePost.isFailure) {
        let valuesError = responsePost.getErrorValue();
        console.log(valuesError);
        return;
      }
      let values = responsePost.getValue();
    });
Actualización

La actualización es muy parecida a la inserción:


  let booking: BookingPost = {
    TravelID: "1",
    BookingID: "1",
    FlightPrice: 24.22,
  };

crudOperations
    .post<Booking, BookingPost>("BOOKING", booking)
    .then((responsePost) => {
      if (responsePost.isFailure) {
        let valuesError = responsePost.getErrorValue();
        console.log(valuesError);
        return;
      }
      let values = responsePost.getValue();
    });

En los parámetros ha actualizar siempre hay que pasarle los campos clave, más los valores a modificar. Si no se pasa los campos claves el servicio devolverá un error.

Activar borrador

En los dos pasos anteriores siempre se inserta y actualiza el borrador, pero si queremos que pase de manera automática de borrador al registro o definitivo. se haría de la siguiente manera:


  let booking: BookingPost = {
    TravelID: "1",
    BookingID: "1",
    BookingDate: new Date(),
    CustomerID: "1",
    CarrierID: "1",
    FlightPrice: 20.22,
    CurrencyCode: "EUR",
  };

crudOperations
    .post<Booking, BookingPost>("BOOKING", booking, {
      v4: { activateDraft: true },
    })
    .then((responsePost) => {
      if (responsePost.isFailure) {
        let valuesError = responsePost.getErrorValue();
        console.log(valuesError);
        return;
      }
      let values = responsePost.getValue();
    });

Si se quiere activar un registro borrador pero no se quiere actualizar ningún campo se haría de la siguiente manera:


crudOperations
    .post<Booking, BookingPost>("BOOKING", {}, {
      v4: { activateDraft: true },
    })
    .then((responsePost) => {
      if (responsePost.isFailure) {
        let valuesError = responsePost.getErrorValue();
        console.log(valuesError);
        return;
      }
      let values = responsePost.getValue();
    });

PATCH, solo OData V2.

Es el método para actualizar registros. Este método a diferencia del PUT permite indicar solo los campos que se necesiten. Por lo que el método PUT no se implementa a favor de este.

A diferencia del método PATCH en Gateway, que solo devuelve si ha ido bien o no, este método devuelve el registro actualizado. Se hace un READ si no hay error en la actualización con la clave pasada por parámetro.

Este método solo se usa en el OData V2, para el V4 se usa el método POST para actualizar registros.

Ejemplo de llamada:

type Booking = {
  TravelID: string;
  BookingID: string;
  BookingDate: Date;
  CustomerID: string;
  CarrierID: string;
};

type BookingPatch = Record<string, any>;

crudOperations.connect("ZUI_BOOKING_O2").then((response) => {
  if (response.isFailure) {
    let valuesError = response.getErrorValue();
    console.log(valuesError);
    return;
  }

  let booking: BookingPatch = {
    FlightPrice: 300.2,
  };

  crudOperations
    .patch<Booking, BookingPatch>(
      "booking",
      { TravelID: "1", BookingID: "1" },
      booking
    )
    .then((responsePost) => {
      if (responsePost.isFailure) {
        let valuesError = responsePost.getErrorValue();
        console.log(valuesError);
        return;
      }
      let values = responsePost.getValue();
      console.log(values);
    });
});