API v1
Punto de acceso para el JSON API de Winfra. A continuación puedes empezar a leer al detalle como esta diseñado el API de Winfra.
- Como funciona el API de Winfra
- Los servicios disponibles
- Definición de los datos
- API para datos masivos
- API cheatsheet (resumen de APIs de referencia)
No tengo tiempo, quiero conectarme ya...
Para acceder al API de winfra necesitas 6 piezas de información. Las tres primeras te proporciona Winfra S.L. Estos datos son comunes para todas las instalaciones de Winfra:
- AUTH_SERVER_URL
- Url del servicio de autenticación de Winfra
- AUTH_USER y AUTH_PASS
- Usuario y contraseña que te identifica como tercero para acceder a cualquier api de winfra.
- API_NOMBRE
- Nombre de api a que vas acceder, como por ejemplo
maestros
ocontabilidad
Siguientes tres piezas te proporciona la empresa con la que vas a conectar. Obviamente cada empresa tendrá su propia configuración.
- DOMAIN
- Identificador de la empresa a que vas a acceder
- DOMAIN_USER y DOMAIN_PASS
- Usuario y contraseña para la empresa a que vas a acceder
- DOMAIN_SERVER_URL
- Url de servicio a que vas a conectar, el url del servidor + el servicio
¿Tienes usuarios y contraseñas? Adelante con el ejemplo o prueba la conexión directamente aquí.
¡Muestrame el código!
Vamos a obtener la lista de los artículos e información del primer artículo. El ejemplo esta en Python, la lógica es igual en otros lenguajes. Para la comunicación utilizo el package requests
.
Vamos a obtener los artículos, eso pertenece al api de los maestros API_NOMBRE="maestros"
.
import requests
# esto el la peticion para el token de autentificacion
peticion_de_token = {
"domain": DOMAIN,
"api": "maestros" # API_NOMBRE
}
# enviamos la peticion al servidor de autenticacion
r = requests.post(AUTH_SERVER_URL + "/api_token/", auth=(AUTH_USER, AUTH_PASS), json=peticion_de_token)
# mostrar el json devuelto
print(r.json())
El resultado de la ejecución
{
'WINFRA-API-TOKEN': 'eyJ0eXAiOiJKV1QiLCJhbGciOi... (mucho mas largo) ...QEyG4O85g9w0mB_e1bOLHg'
}
El servicio es /api_v1/articulos/
import requests
r = requests.get(
DOMAIN_SERVER_URL + "/api_v1/articulos/",
auth=(DOMAIN_USER, DOMAIN_PASS),
headers={"WINFRA-API-TOKEN": "eyJ0eXAiOiJKV1QiLCJhbGciOi... (mucho mas largo) ...QEyG4O85g9w0mB_e1bOLHg"}
)
print(r.json())
Y la respuesta:
[
{
"codigo": "1",
"hash": 0,
"id": "8fd593d0-f7d8-44c9-bfb9-026d823b3d95",
"nombre": "San Miguel 1/3",
"tipo": "producto"
},
... (muchos mas artículos por aquí) ...
{
"codigo": "10",
"hash": 0,
"id": "1fcb8b44-8a32-4dfa-8639-39fa5df3a8b0",
"nombre": "San Miguel 1/5",
"tipo": "producto"
}
]
Ahora para obtener un artículo detallado tenemos que incluir su id
en la petición.
import requests
r = requests.get(
DOMAIN_SERVER_URL + "/api_v1/articulos/1d3f74f8-4494-48ca-b294-d3ad6d2cd437",
auth=(DOMAIN_USER, DOMAIN_PASS),
headers={"WINFRA-API-TOKEN": "eyJ0eXAiOiJKV1QiLCJhbGciOi... (mucho mas largo) ...QEyG4O85g9w0mB_e1bOLHg"}
)
print(r.json())
Con el resultado como este:
{
"adjuntos": [],
"codigo": "1045",
"dimension1_codigo": "",
"dimension1_descripcion": "",
"dimension2_codigo": "",
"dimension2_descripcion": "",
"fabricante_codigo": "199",
"fabricante_descripcion": "COOPERATIVA VINICOLA UNION DEL VALLE",
"formatos": [
{
"codigo": "1045",
"descripcion": "",
"equivalencia": 1.0,
"id": "3b3ab89d-427f-4a79-9863-2060ef5c9d0c",
"nombre": "VIVAZ TINTO CRIANZA TIERRA LEON",
"tipo": "Caja"
}
],
"hash": 0,
"id": "1d3f74f8-4494-48ca-b294-d3ad6d2cd437",
"impuestos": [
{
"base": 100.0,
"descripcion": "IVA general",
"grupo": "general",
"iva": 21.0,
"recargo": 5.2
}
],
"marca": "",
"nombre": "VIVAZ TINTO CRIANZA TIERRA LEON",
"organizacion_venta": "Bebidas",
"subtipo": "",
"subtipo_descripcion": "",
"tipo": "producto",
"tipo_descripcion": "Producto"
}
Código en c#
para obtener la lista de los artículos. En el ejemplo utiliza la clase WebClient
que no esta recomendada en la nuevas versiones de .net pero es compatible desde versión 2.0.
Las funciones auxiliares para aceptar los certificados y para procesar posibles errores.
static bool CertValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
// acepta todos los certificados para utilizar el api con el certificado firmado por winfra
return true;
}
static void HandleWebError(WebException ex)
{
// controlo el estado de resultado y saco en error devuelto por el servidor
if (ex.Response != null)
{
int status = (int)((HttpWebResponse)ex.Response).StatusCode;
if (status == 401 || status == 422 || status == 555)
{
using (var sr = new StreamReader(ex.Response.GetResponseStream()))
{
string errjson = sr.ReadToEnd();
throw new ApplicationException(errjson);
}
}
}
throw ex;
}
Para empezar configuramos el cliente y registramos los usuarios y contraseñas con sus urls.
ServicePointManager.Expect100Continue = false;
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CertValidation);
// tengo dos credenciales diferentes para el los dos servidores
var creds = new CredentialCache();
creds.Add(new Uri(AUTH_SERVER_URL + "api_token/"), "Basic", new NetworkCredential(AUTH_USER, AUTH_PASS));
creds.Add(new Uri(DOMAIN_SERVER_URL + "api_v1/"), "Basic", new NetworkCredential(DOMAIN_USER, DOMAIN_PASS));
Obtenemos el token
string token = "";
using (var wc = new WebClient())
{
wc.Credentials = creds;
// obtener el token
try
{
// como serializar y deserializar el json en c# depende de versiones de framework o librerias externas
// crearé y leeré el JSON como strings.
string peticion = string.Format("{{\"domain\": \"{0}\", \"api\": \"{1}\"}}", DOMAIN, API_NOMBRE);
byte[] data = wc.UploadData(AUTH_SERVER_URL + "api_token/", Encoding.UTF8.GetBytes(peticion));
string json = Encoding.UTF8.GetString(data);
string[] partes = json.Split('"');
token = partes[3];
}
catch (WebException ex)
{
HandleWebError(ex);
}
}
Obtenemos los artículos proporcionando el token
using (var wc = new WebClient())
{
wc.Credentials = creds;
// obtener los articulos
try
{
// anado el token para acceder a api
wc.Headers.Add("WINFRA-API-TOKEN", token);
string json = wc.DownloadString(DOMAIN_SERVER_URL + "api_v1/articulos/");
}
catch (WebException ex)
{
HandleWebError(ex);
}
}
La implementación de Javascript que utilizamos en la herramienta de pruebas.
La funcion implementa la llamada a web y devuelve null
en caso de error o JSON con el resultado.
async function call_http(method, url, user, pass, token=null, data=null) {
// implementa la llamada a web y devuelve el json
// o null si ha ocurido algun error.
// Los errores van directamente a log.
var headers = new Headers()
headers.set('Authorization', 'Basic ' + window.btoa(unescape(encodeURIComponent(user + ":" + pass))));
if (token !== null) {
headers.set('WINFRA-API-TOKEN', token);
}
var req = {}
req.method = method;
req.headers = headers;
if (data !== null) {
req.body = JSON.stringify(data)
}
var sc;
json = await fetch(url, req)
.then(function(response) {
sc = response.status
console.log('Status: ' + sc + ' ' + response.statusText)
if (sc == 200 | sc == 401 | sc == 422 | sc == 555) {
return response.json()
}
})
.catch(function(error) {
console.log('ERROR: ' + error.message);
});
if (json) {
if (sc == 200) {
return json
} else {
console.log("ERROR: " + json.error)
return null
}
} else {
return null
}
}
La lógica de llamada a los servicios:
gettoken = call_http("POST", AUTH_SERVER_URL + "api_token/", AUTH_USER, AUTH_PASS, null, {"domain" : DOMAIN, "api": API_NOMBRE});
gettoken.then(function(json) {
if (json !== null) {
// tenemos un valor de json devuelto
token = json["WINFRA-API-TOKEN"]
if (token) {
// llamada a api indicado, incluyendo el token
getapi = call_http("GET", DOMAIN_SERVER_URL + "api_v1/articulos/", DOMAIN_USER, DOMAIN_PASS, token, null)
getapi.then(function(json) {
if (json !== null) {
// tenemos un resultado
console.log(json)
}
})
}
}
})
Detalles de API y la estructura de los datos estan en la correspondiente documentación.