navidev-adt-api
TypeScript icon, indicating that this package has built-in type declarations

0.4.6 • Public • Published

Objetivo

El objetivo es disponer de una API que permita conectar con el ADT, Abap Developer Tools, para permitirnos crear programa, clases, mensajes, etc.. Desde cualquier aplicación hecha en JS/TS, ya que esta API ha sido creada en node para que pueda usarse en cualquier framework de JS, como React.

Esta herramienta o API se inspira, por no decir que algunas partes se basan en esa API, en la Abap ADT API creada por Marcello Urbani para su extensión de VS Code llamada ABAP Remote FS.

La diferencia entre ambas API , aparte que la mia tiene menos funcionalidad al menos incialmente, es que la he creado intentado usar metodología DDD, para tener una mejor estructuración. Y algunas cosas de que Marcello las hace de una manera yo las he planteado de otra manera.

Y me gustaría destacar el esfuerzo de Marcello para crear semejante API y extensión de VS Code.

Instalación

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

pnpm install navidev-adt-api

o

npm install navidev-adt-api

Como usarla

En nuestro código lo primero es importarla de la siguiente manera:

import AdtAPI from "navidev-adt-api/AdtAPI"

A destacar lo siguiente:

  • Todas las llamadas devuelven siempre una Promesa que hay que tratar para recuperar los valores o los errores.
  • La clase devuelve excepciones pero no es necesario capturarla con un try..catch en caso de errores de cualquier índole.

En el siguiente apartado se explica como recuperar los valores y errores

Como recuperar valores y errores

A modo de ejemplo pongo la llamada que nos devuelve una lista con todos los objetos del ADT:

Ejemplo de llamada:

adtApi.repositoryreadTypesStructure().then((response) => {
	if (response.isSuccess) {
		let values = response.getValue() as RepositoryTypesStructure;
		console.log(values);
	} else if (response.isFailure) {
		let adtException = response.getErrorValue() as AdtException;
		console.log(adtException);
	}
});

La respuesta tiene dos variables: isSucces que será true si la petición ha ido correctamente, y recuperaremos los valores a través del método getValue, y la segunda isFailure que será true si se ha producción cualquier tipo de error del proceso, el error se recuperá mediante el metodo getErrorValue. El error devuelto será siempre del tipo AdtException. Habrá que mirar los campos informados que variarán según a la API que se llame.

Este ejemplo se hace un else if para mirar si ha fallado a modo de ejemplo completo, pero realmente si isSuccess es false es que se ha producido un error que habrá que procesarlo tal como se ve en el ejemplo.

Esta manera de recuperar los valores y errores será igual para toda la API.

API

Toda la funcionalidad de la API estará dentro de la clase AdtAPI que se instanciará de la siguiente manera:

let adtApi = new AdtAPI({
	client: "001",
	language: "EN",
	password: "password",
	username: "DEVELOPER",
	urlBase: "http://vhcalnplci.dummy.nodomain:8000",
});

Una vez instanciada se podrá acceder a todos los método disponibles que se explican a continuación

Login

Método: Login

Este método no es necesario porque si se llama a cualquier método y se conecta de manera automática. Aún así este método puede servir para validar que se puede acceder al sistema.

Ejemplo de llamada:

adtAPI.login().then((response) => {
		if( response.isSuccess){
            console.log("Connected")
        }
		else{
            let adtException = response.getErrorValue() as AdtException;
		    // Tratmiento del error
        }

	});

Repositorio

Listado de tipos de estructura(Arbol ADT)

Método: repositoryReadTypesStructure

Devuelve el listado de los tipos en el arbol de estructura en ADT. Son los nodos que podemos ver en la SE80 o Eclipse.

Ejemplo de llamada:

adtApi.repositoryReadTypesStructure().then((response) => {
	if (response.isSuccess) {
		let values = response.getValue() as RepositoryTypesStructure;
		console.log(values);
	} else  {
		let adtException = response.getErrorValue() as AdtException;
		// Tratmiento del error
	}
});

Listado de tipos objetos

Método: repositoryReadObjectTypes

Devuelve el listado de los tipos de objetos de ADT: Programa, clases, Webdynpro, etc..

Ejemplo de llamada:

adtApi.repositoryReadObjectTypes().then((response) => {
	if (response.isSuccess) {
		let values = response.getValue() as RepositoryObjectTypes;
		console.log(values);
	} else {
		let adtException = response.getErrorValue() as AdtException;
		console.log(adtException);
	}
});

Listado de tipos de objetos que se pueden validar

Método: repositoryReadCheckRuns

Devuelve el listado de los tipos de objetos que se pueden validar o compilar: programas, clases, funciones, diccionario, etc.

Ejemplo de llamada:

adtApi.repositoryReadCheckRuns().then((response) => {
	if (response.isSuccess) {
		let values = response.getValue() as RepositoryCheckRuns;
		console.log(values);
	} else {
		let adtException = response.getErrorValue() as AdtException;
		console.log(adtException);
	}
});

Metadatos para poder buscar objetos

Método: repositorySearchMetadata

Devuelve la combinación de tipos objetos que se pueden usar para hacer búsquedas de objetos. Ejemplo: En clases nos devolverá el tipo CLASS y los subtipos: OA(atributo de clase), OC(clase), OCE(evento), etc..

Los campos destacados que devuelve el método son:

  • trobjtype -> Tipo de objeto: CLAS (clase), DEVC(paquete), etc
  • legacy_type -> Subtipo: OA(atributo de clase), OC(clase), OCE(evento), etc..
  • descriptionsingular y description_plural -> Descripción del campo _legacy_type
  • descriptionencl_object -> Descripción del campo _trobjtype

Ejemplo de llamada:

adtApi.repositorySearchMetadata().then((response) => {
	if (response.isSuccess) {
		let values = response.getValue() as SearchMetadatas;
		console.log(values);
	} else {
		let adtException = response.getErrorValue() as AdtException;
		console.log(adtException);
	}
});

Búsqueda de objetos

Método: repositoryIndividualSearchObjects

Realiza la busqueda individual de objetos, es decir, por un tipo y subtipo. Al método se le pasa el tipo, subtipo y el texto a buscar. El texto a buscar puede ser un patron: *zclmyclass** para que devuelva los posibles valores.

Para búsqueda rápidas, como verificar si existe una clase o devolver paquetes que tengan un patrón, es recomendable usar el método repositoryQuickSearch de la API ya que no es necesario saberse el subtipo en concreto.

Los campos que devuelve el método son:

  • uri -> URL del objeto, esta URL se usará para obtener sus contenido, activación, grabación, etc.
  • type -> Tipo de objeto
  • name -> Nombre del objeto
  • packageName -> Paquete al que esta asociado

Ejemplo de llamada:

adtApi
	.repositoryIndividualSearchObjects(
		"CLAS",
		"OC",
		"zcl_zsap_tools_core_dpc_ext"
	)
	.then((response) => {
		if (response.isSuccess) {
			let values = response.getValue() as SearchObjects;
			console.log(values);
		} else {
			let adtException = response.getErrorValue() as AdtException;
			console.log(adtException);
		}
	});

En este ejemplo de llamada se le pasa el tipo "CLAS" y el subtipo "OC" (clase en si misma) y el nombre de la clase a búscar.

Búsqueda rápida de objetos

Método: repositoryQuickSearch

Muy parecido a la búsqueda individual de objetos pero aquí la diferencia es que solo se pasa el tipo de objeto y el texto o patrón del objeto. Este método es el más indicando para búsquedas estilo:"Dame todos los paquetes que comiencen por ZCA*".

Los campos que devuelve el método son:

  • uri -> URL del objeto, esta URL se usará para obtener sus contenido, activación, grabación, etc.
  • type -> Tipo de objeto
  • name -> Nombre del objeto
  • packageName -> Paquete al que esta asociado

Ejemplo de llamada:

adtApi.repositoryQuickSearch("DEVC", "zca*").then((response) => {
	if (response.isSuccess) {
		let values = response.getValue() as SearchObjects;
		console.log(values);
	} else {
		let adtException = response.getErrorValue() as AdtException;
		console.log(adtException);
	}
});

Paquetes

Listado de clases de desarrollo o paquetes

Método: packageReadPackages

Devuelve el listado todos los paquetes de desarrollo del sistema

Ejemplo de llamada:

adtApi.packageReadPackages().then((response) => {
	if (response.isSuccess) {
		let values = response.getValue() as PackagesList;
		console.log(values);
	} else {
		let adtException = response.getErrorValue() as AdtException;
		console.log(adtException);
	}
});

Contenido de un paquete

Método: packageReadContent

Devuelve el contenido de un paquete. El contenido devuelto es parecido a la estructura que vemos en el Eclipse: |- Nombre del paquete |-- categories -> Categorias de los objetos: Codigo fuente, diccionario, clases de mensaje, etc. |---- objectTypes -> Tipos de objeto clases, programas, dominios, etc. |----- objects -> Objetos del tipo: Nombre del objeto. De este nodo destacar el valor del campo objectUri, esta es la URL que se le pasará a otros servicio como el que obtiene estructuras, etc.. y el campo objectName que nos servirá en método como el de activar |-- Subpaquetes -> Objeto que contiene la misma estructura que la anterior de manera recursiva.

Ejemplo de llamada:

adtApi.packageReadContent("ZSAP_TOOLS").then((response) => {
	if (response.isSuccess) {
		let values = response.getValue() as PackageContent;
		console.log(values);
	} else {
		let adtException = response.getErrorValue() as AdtException;
		console.log(adtException);
	}
});

Contenido de un paquete en formato plano

Método: packageReadContentFlat

Se basa en el método packageReadContent pero en vez de devolver los paquetes en subniveles los devuelve en un formato plano:

|- Nivel |- Paquete superior o padre |- Nombre del paquete |-- categories -> Categorias de los objetos: Codigo fuente, diccionario, clases de mensaje, etc. |---- objectTypes -> Tipos de objeto clases, programas, dominios, etc. |----- objects -> Objetos del tipo: Nombre del objeto. De este nodo destacar el valor del campo objectUri, esta es la URL que se le pasará a otros servicio como el que obtiene estructuras, etc.. y el campo objectName que nos servirá en método como el de activar

Ejemplo de llamada:

adtApi.packageReadContentFlat("ZSAP_TOOLS").then((response) => {
	if (response.isSuccess) {
		let values = response.getValue() as PackageContentsFlat;
		console.log(values);
	} else {
		let adtException = response.getErrorValue() as AdtException;
		console.log(adtException);
	}
});

Objeto

Obtener la estructura

Método: objectReadStructure

Devuelve la estructura de un objeto: variables, constantes, métodos, interfaces y su posición. Es decir, lo que en el eclipse se ve en el outline. Dependiendo del tipo de objeto devuelve varias posiciones dividido por secciones. Ejemplo si tenemos esta declaración:

    INTERFACES zif_spt_core_app .

Nos devolverá dos secciones: definitionIdentifier donde indica linea y columna donde comienza y finaliza el texto zif_spt_core_app. Y otro registro con el bloque definitionBlock donde indica linea y columna donde comienza y finaliza el texto INTERFACES zif_spt_core_app .

Al método se le pasa la URL del objeto que se quiere obtener los datos. Esa URL se recupera de la lectura de los objetos de los paquetes en el array objects campo objectUri.

La estructura que devuelve es:

|- Campos del objeto y tipo |-- structureElements Array con las variables, constantes, etc.. que se usa |--- blockInfo Array con la información de los bloques y su posiciones.

Ejemplo de llamada:

    adtApi
	.objectStructure("/sap/bc/adt/oo/classes/zcl_spt_apps_base")
	.then((response) => {
		if (response.isSuccess) {
			let values = response.getValue() as ObjectStructure;
			console.log(values);
		} else {
			let adtException = response.getErrorValue() as AdtException;
			console.log(adtException);
		}
	});

Validación de sintaxis

Método: objectCheck

Hace la validación de sintaxis de un objeto. La validación de la sintaxis se puede hacer de dos maneras:

  • Pasandole la URL directamente esto hace que se valide la versión activa del objeto.

Ejemplo de como se haría la llamada en este caso:

adtApi
	.objectCheck("/sap/bc/adt/oo/classes/zcl_spt_apps_base")
	.then((response) => {
		if (response.isSuccess) {
			let values = response.getValue() as ObjectCheckRun;
			console.log(values);
		} else {
			let adtException = response.getErrorValue() as AdtException;
			console.log(adtException);
		}
	});
  • Pasandole la URL del objeto y los artifacts. El artifact son los subcomponentes del objeto y el contenido del mismo. El contenido hay que pasarlo en base64. Ejemplo de llamada en un clase:
adtApi
	.objectCheck("/sap/bc/adt/oo/classes/zcl_test_adt", [
		{
			sourceUri:
				"includes/implementations",
			artifactContent:
				"KiIqIHVzZSB0aGlzIHNvdXJjZSBmaWxlIGZvciB0aGUgZGVmaW5pdGlvbiBhbmQgaW1wbGVtZW50YXRpb24gb2YNCioiKiBsb2NhbCBoZWxwZXIgY2xhc3NlcywgaW50ZXJmYWNlIGRlZmluaXRpb25zIGFuZCB0eXBlDQoqIiogZGVjbGFyYXRpb25zDQoNCmNsYXNzIGxjbF9jb250cm9sbGVyIERFRklOSVRJT04uDQpwdWJsaWMgc2VjdGlvbi4NCm1ldGhvZHMgbWV0b2RvMi4NCg0KRU5EQ0xBU1MuDQoNCmNsYXNzIGxjbF9jb250cm9sbGVyIElNUExFTUVOVEFUSU9OLg0KRU5EQ0xBU1Mu",
		},
		{
			sourceUri:
				"source/main",
			artifactContent:
				"Y2xhc3MgWkNMX1RFU1RfQURUIGRlZmluaXRpb24NCiAgcHVibGljDQogIGZpbmFsDQogIGNyZWF0ZSBwdWJsaWMgLg0KDQpwdWJsaWMgc2VjdGlvbi4NCg0KICBkYXRhIE1WX1ZBUjIgdHlwZSBTVFJJTkcgLg0KDQogIG1ldGhvZHMgTUVUT0RPMSAuDQogIFBST1RFQ1RFRCBTRUNUSU9OLg0KICBQUklWQVRFIFNFQ1RJT04uDQpFTkRDTEFTUy4NCg0KDQoNCkNMQVNTIFpDTF9URVNUX0FEVCBJTVBMRU1FTlRBVElPTi4NCg0KDQogIE1FVEhPRCBtZXRvZG8xLg0KICAgIFdSSVRFOi8gJ2RkJy4uDQogIEVORE1FVEhPRC4NCkVORENMQVNTLg==",
		}
	])
	.then((response) => {
		if (response.isSuccess) {
			let values = response.getValue() as ObjectCheckRun;
			console.log(values.messagesList);
		} else {
			let adtException = response.getErrorValue() as AdtException;
			console.log(adtException);
		}
	});

Al ser un array se pueden pasar varios includes, tal como se ve en el ejemplo anterior. Eso si, en la versión de ABAP del trial versión que estoy usando si ambos includes tienen errores de código devuelve solo el primer error. Eso si, la API esta preparada para devolver todos los posibles mensajes que devuelta el ADT.

La URL principal del objeto viene cuando se leen los objetos de un paquete, en el array objects esta el campo objectUri con su valor.

El sourceUri de los artifacts depende del objeto que se esta procesando. En el caso de las clases se obtiene cuando se lee su contenido con el método classReadContent encontraremos el valor en el campo sourceUri en el array sourceIncludes.

En ambos tiposde llamada la estructura que devuelve es:

|- Campos de salida genericos de la validación. |-- messagesList Listado de con los mensajes devuelve en la validación. En el campo type con los valores: 'E' error y 'W' warning. shortText con el mensaje, pos posición del mensaje y quickFix si propuesta para arreglo rapido.

Bloqueo de objetos

Método: objectLock

Bloquea un objeto antes de poder editarlo. Si el objeto ya esta bloqueado se recupera quien lo esta bloqueando en la excepción que se recupera.

Al método se le pasa la URL que se recupera de la lectura de los objetos de los paquetes en el array objects campo objectUri.

En la respuesta del bloqueo hay que tener en cuenta dos campos para la edición:

  • lockHandle -> Devuelve el ID del bloqueo que se pasará al grabar y desbloquear el objeto.
  • corrnr -> Orden de transporte asociado al objeto, que se pasará al grabar el objeto.

Ejemplo de llamada:

adtApi
	.objectLock("/sap/bc/adt/oo/classes/zcl_spt_apps_base")
	.then((response) => {
		if (response.isSuccess) {
			let values = response.getValue() as ObjectLock;
			console.log(`lock handle: ${values.lockHandle}`);
			console.log(`Transport order: ${values.corrnr}`);
		} else {
			let adtException = response.getErrorValue() as AdtException;
			console.log(adtException.message);
		}
	});

Desbloqueo de objetos

Método: ObjectUnlock

Desbloquea un objeto. Al método se le pasa la URL que se recupera de la lectura de los objetos de los paquetes en el array objects campo objectUri, y se le pasa el valor del campo lockHandle que se recupera en el bloqueo.

El método no devuelve nada si todo ha ido bien.

Ejemplo de llamada:

adtApi
	.objectLock("/sap/bc/adt/oo/classes/zcl_spt_apps_base")
	.then((response) => {
		if (response.isSuccess) {
			let values = response.getValue() as ObjectLock;
			console.log(`lock handle: ${values.lockHandle}`);
			console.log(`Transport order: ${values.corrnr}`);
			adtApi
				.ObjectUnlock(
					"/sap/bc/adt/oo/classes/zcl_spt_apps_base",
					values.lockHandle
				)
				.then((response) => {
					if (response.isSuccess) {
					} else {
						let adtException = response.getErrorValue() as AdtException;
						console.log(adtException.message);
					}
				});
		} else {
			let adtException = response.getErrorValue() as AdtException;
			console.log(adtException.message);
		}
	});

Activación de objetos

Método: objectActivate

Activa un objeto. Al método se le pasa la URL que se recupera de la lectura de los objetos de los paquetes en el array objects campo objectUri, y se le pasa el nombre del objeto, campo objectName que también estado en el array donde recuperamos el objectUri.

El método no devuelve nada si todo ha ido bien. Si hay errores de sintaxis en la activación los mensajes vienen en nodo messages.

Ejemplo de llamada:

adtApi
	.objectActivate("/sap/bc/adt/oo/classes/zcl_test_adt", "ZCL_TEST_ADT")
	.then((response) => {
		if (response.isSuccess) {
			let values = response.getValue() as ObjectActivate;
			if (values.messages) console.log(values);
			else console.log("ok");
		} else {
			let adtException = response.getErrorValue() as AdtException;
			console.log(adtException);
		}
	});

Clases

Contenido de una clase

Método: classReadContent

Devuelve el contenido de una clase. Ese contenido se separa en dos partes:

  1. Metadatos: nombre de clase, tipo, datos de creación y modificación
  2. Includes con el código fuente de cada parte de la clase: definiciones/implementaciones clases locales, macros, testing y código principal. El código fuente principal esta en el include, campo includeType, "main".

Al método se le pasa la URL del objeto que se recupera al leer el contenido de los objetos de las clases de desarrollo.

Ejemplo de llamada:

adtApi.classReadContent("/sap/bc/adt/oo/classes/zcl_spt_apps_base").then((response) => {
	if (response.isSuccess) {
		let values = response.getValue() as ClassContent;
		console.log(values);
	} else {
		let adtException = response.getErrorValue() as AdtException;
		console.log(adtException);
	}
});

Readme

Keywords

Package Sidebar

Install

npm i navidev-adt-api

Weekly Downloads

8

Version

0.4.6

License

MIT

Unpacked Size

209 kB

Total Files

130

Last publish

Collaborators

  • irodrigob