SDK Multiplataforma en C logo

SDK Multiplataforma en C

Servicios Web JSON en C/C++

❮ Anterior
Siguiente ❯

El formato JSON es el más utilizado para el intercambio de datos en la Web. Vamos a ver como llamar a un servicio Web desde una aplicación C/C++ y "traducir" su respuesta JSON a los objetos que forman el modelo de datos.


JSON JavaScript Object Notation, es un formato de datos en modo texto que permite representar de manera sencilla tipos básicos, objetos y arrays. Aunque su uso se ha popularizado en el ámbito Web puede utilizarse también para otros fines, como por ejemplo, archivos de configuración o intercambio local. Su sintaxis es fácil de entender para los humanos y sencilla de procesar para las máquinas. En (Listado 1) reproducimos un pequeño fragmento de la respuesta JSON de un servicio Web de ejemplo:

Listado 1: Fragmento JSON devuelto por un Web Service.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
    "code":0,
    "size":80,
    "data":[
    {"id":0,
    "code":"i7-8700K",
    "description":"Intel BX80684I78700K 8th Gen Core i7-8700K Processor",
    type":0,
    "price":374.8899999999999863575794734060764312744140625,
    "image":"cpu_00.jpg",
    "image64":"\/9j\/4AAQSkZJRgABAQ....
    },
    ...
}

En su estructura podemos encontrar estos tipos de datos:

  • Booleanos: Representados por las constantes true o false.
  • Números: Utiliza la notación exponencial de C para valores en coma flotante: 23, .76, -0.54 o 5.6e12 son ejemplos válidos de valores numéricos. JSON no distingue entre enteros, negativos o reales.
  • Cadenas: Cualquier texto entre comillas se considera una cadena. Admite cualquier carácter Unicode en UTF-8 o mediante la secuencia de escape \uXXXX para indicar el codepoint.
  • Objetos: Están delimitados por llaves y compuestos por varios campos separados por comas. Cada campo lo forman un identificador (cadena) seguido del carácter dos puntos y un valor que puede ser cualquier tipo simple, objeto u array (Listado 2).
  • Listado 2: Objeto JSON
    1
    2
    3
    4
    5
    6
    7
    
    {
        "field1" : true,
        "field2" : 24.67,
        "field3" : "Hello Pibe",
        "field4" : [1, 2, 4, 8.4],
        "field5" : { "x" : 34.32, "y" : -6.19 }
    }
    
  • Arrays: Listas de valores delimitados por cochetes [ ... ] y separados por comas. Los valores no tienen porqué ser del mismo tipo como suele ocurrir en algunos lenguajes de programación (Listado 3).
  • Listado 3: Array JSON
    1
    2
    3
    
    [
        18, "Hello Pibe", true, { "x" : 34.32, "y" : -6.19 }
    ]
    
  • null: Indica la ausencia de valor.
  • Binarios: JSON no soporta datos binarios por lo que objetos opacos (imágenes, por ejemplo) deben ser codificados en texto y transmitidos como un valor de tipo cadena. El formato más extendido y soportado globalmente es el Base64 donde cada carácter representa 6 bits de información.

1. Llamar a un servicio Web

Lo primero que debemos hacer es conectar con servicio Web mediante HTTP para realizar la consulta y obtener el JSON de respuesta. Tenemos dos formas de hacerlo. La más directa es utilizar el método http_dget (Listado 4).

Listado 4: Obtener un recurso Web mediante HTTP.
1
Stream *stm = http_dget("serv.nappgui.com", 80, "/dproducts.php", NULL);

Esta llamada es muy simple y útil para obtener recursos de forma directa, donde no es necesario indicar parámetros ni configurar la petición. Para otro tipo de peticiones, deberemos crear un objeto Http (Listado 5).

Listado 5: Llamada a un servicio Web con parámetros
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Http *http = http_create("serv.nappgui.com", 80, NULL);
if (http != NULL)
{
    Stream *stm = stm_memory(4096);
    http_param(http, "user", "brian");
    http_param(http, "pass", "1234");
    if (http_get(http, "/duser.php", stm, NULL) == TRUE)
    {
        ...
    }

    http_destroy(&http);
}

Si todo ha ido bien, tendremos en Stream *stm la respuesta del servidor en ambos casos. El siguiente paso será "parsearla" para convertir la secuencia de caracteres que forman el JSON a objetos binarios para su uso desde la aplicación (Listado 6). En Lectura JSON se detalla como vincular los campos del JSON mediante el registro DBind.

Listado 6: Traducir un JSON a un objeto C.
1
PJson *json = json_read(stm, NULL, PJson);

2. Programa completo

Listado 7: howto/htjson/htjson.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/* JSON download and parsing */
    
#include "draw2dall.h"
#include "httpreq.h"
#include "json.h"

/*---------------------------------------------------------------------------*/

typedef struct _product_t Product;
typedef struct _pjson_t PJson;

struct _product_t
{
    uint32_t type;
    String *code;
    String *description;
    Image *image64;
    real32_t price;
};

struct _pjson_t
{
    int32_t code;
    uint32_t size;
    ArrPt(Product) *data;
};

/*---------------------------------------------------------------------------*/

int main(int argc, char *argv[])
{
    Stream *json = NULL;
    PJson *pjson = NULL;

    unref(argc);
    unref(argv);
    draw2d_start();

    /* Data binding */
    dbind(Product, uint32_t, type);
    dbind(Product, String*, code);
    dbind(Product, String*, description);
    dbind(Product, Image*, image64);
    dbind(Product, real32_t, price);
    dbind(PJson, int32_t, code);
    dbind(PJson, uint32_t, size);
    dbind(PJson, ArrPt(Product)*, data);

    /* WebService request */
    json = http_dget("serv.nappgui.com", 80, "/dproducts.php", NULL);

    /* JSON Parsing and stream close */
    if (json != NULL)
    {
        /* Json knows how to parse 'dbind' data types */
        pjson = json_read(json, NULL, PJson);
        stm_close(&json);
    }
    else
    {
        bstd_printf("WebService Error.");
    }

    if (pjson != NULL)
    {
        bstd_printf("JSON readed. Code: %d\n", pjson->code);
        bstd_printf("Readed %d products\n", pjson->size);
    
        arrpt_foreach(product, pjson->data, Product)
            uint32_t width, height;
            image_size(product->image64, &width, &height);
            bstd_printf("%2d %-20s %8.2f Image:%dx%dpx\n", product_i + 1, tc(product->code), product->price, width, height);
        arrpt_end()

        /* 'dbind' knows how to destroy registered data types */
        dbind_destroy(&pjson, PJson);
    }
    else
    {
        bstd_printf("JSON Processing Error.");
    }

    draw2d_finish();
    return 0;
}

Listado 8: Salida del programa.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
JSON readed. Code: 0
Readed 80 products
 1 i7-8700K               374.89 Image:160x160px
 2 G3930                   51.95 Image:125x160px
 3 i7-7700K               329.99 Image:138x160px
 4 Ryzen-5-1600           194.99 Image:160x160px
 5 i5-8600K               256.89 Image:160x160px
 6 G4400                   58.95 Image:160x160px
 7 G3900                   46.00 Image:160x160px
 8 i5-8400                189.99 Image:148x160px
 9 PentiumG                71.95 Image:146x160px
10 i5-7500                197.89 Image:160x160px
11 Ryzen-7-1700           289.99 Image:160x160px
12 i3-7100                114.99 Image:160x160px
13 Ryzen-7-1800X          349.00 Image:160x160px
14 i7-8700                312.00 Image:160x160px
15 Ryzen-3-1300X          124.99 Image:160x160px
16 i3-8100                119.00 Image:160x160px
17 Ryzen-3-1200           104.99 Image:160x160px
18 i5-7600K               229.00 Image:125x160px
19 Ryzen-5-1500X          174.99 Image:160x160px
20 Ryzen-5-1600X          224.99 Image:160x160px
21 RX-580                 489.99 Image:160x160px
22 HD-6450                 44.96 Image:160x160px
23 GTX-1060               449.99 Image:160x160px
24 GTX-1060-SC            419.98 Image:160x160px
25 GTX-1080               439.99 Image:160x160px
26 GTX-1090               482.99 Image:160x160px
27 GT-710                  45.74 Image:160x160px
28 GTX-1050               238.49 Image:160x160px
29 GTX-1040               176.95 Image:160x160px
30 GTX-1080-FTW           915.99 Image:160x160px
31 GTX-1080-Ti           1149.97 Image:160x160px
32 R7-240                  59.99 Image:160x160px
33 GTX-1070-SC            739.99 Image:160x160px
34 GT-1030                 95.00 Image:160x160px
35 210                     37.74 Image:160x160px
36 GT-710                  46.15 Image:160x160px
37 GTX-1010               199.90 Image:160x160px
38 GTX-1100               429.99 Image:160x160px
39 GTX-1040               463.00 Image:160x160px
40 GT-710-LP               34.99 Image:160x160px
41 Blue-1TB                49.00 Image:160x160px
42 2TB-BarraCuda           59.89 Image:160x160px
43 2TB-FireCuda            94.99 Image:160x160px
44 Red-4TB                132.99 Image:160x160px
45 4TB-BarraCuda           96.99 Image:160x160px
46 1TB-BarraCuda           49.65 Image:160x160px
47 1TB-BarraCuda           44.99 Image:160x160px
48 2TB-FireCuda            99.99 Image:160x160px
49 Blue-2TB                65.99 Image:160x160px
50 Purple-4TB             114.68 Image:133x160px
51 2TB-BarraCuda           84.29 Image:160x160px
52 3TB-BarraCuda           84.99 Image:160x160px
53 Black-1TB               64.99 Image:160x160px
54 Blue-4TB               107.99 Image:160x160px
55 Black-1TB               72.99 Image:125x160px
56 Blue-1TB                45.99 Image:116x160px
57 Blue-1TB                52.99 Image:160x160px
58 Red-2TB                 84.99 Image:160x160px
59 1TB-Firecuda            59.99 Image:160x160px
60 Red-8TB                246.99 Image:160x160px
61 45-SB-we                37.95 Image:159x160px
62 12-SB-we                39.98 Image:160x160px
63 14-SB-z                 94.97 Image:160x160px
64 77-AS-2                 29.99 Image:160x160px
65 99-SB-rb                55.53 Image:160x160px
66 54-AS-e                 39.99 Image:160x160px
67 ST-45092                17.63 Image:160x160px
68 55-SB-Zx               124.87 Image:153x160px
69 GE-PCI-41               12.99 Image:160x160px
70 00-SB-XF                33.45 Image:102x160px
71 5-SB-AE                149.90 Image:160x160px
72 99-PI-r                 22.90 Image:160x160px
73 67-SB-xf                66.66 Image:160x160px
74 88-AS-e                104.14 Image:160x160px
75 37-AS-x                149.99 Image:160x160px
76 54-SI-x1                35.99 Image:160x160px
77 52-PI-0                 11.99 Image:160x160px
78 82-AS-II               223.98 Image:160x160px
79 22-SB-tg                99.99 Image:160x160px
80 38-DI-xs                14.95 Image:160x160px
❮ Anterior
Siguiente ❯