-start a lib for REST and json:api
[oweals/gnunet.git] / src / rest / rest.c
1 /*
2       This file is part of GNUnet
3       Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors)
4
5       GNUnet is free software; you can redistribute it and/or modify
6       it under the terms of the GNU General Public License as published
7       by the Free Software Foundation; either version 3, or (at your
8       option) any later version.
9
10       GNUnet is distributed in the hope that it will be useful, but
11       WITHOUT ANY WARRANTY; without even the implied warranty of
12       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13       General Public License for more details.
14
15       You should have received a copy of the GNU General Public License
16       along with GNUnet; see the file COPYING.  If not, write to the
17       Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18       Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * @file rest/rest.c
23  * @brief helper library to create JSON REST Objects and handle REST
24  * responses/requests.
25  * @author Martin Schanzenbach
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_rest_lib.h"
30 #include "microhttpd.h"
31 #include <jansson.h>
32
33
34 struct JsonApiResource
35 {
36   /**
37    * DLL
38    */
39   struct JsonApiResource *next;
40
41   /**
42    * DLL
43    */
44   struct JsonApiResource *prev;
45
46   /**
47    * Resource content
48    */
49   json_t *res_obj;
50 };
51
52
53 struct JsonApiResponse
54 {
55   /**
56    * DLL Resource
57    */
58   struct JsonApiResource *res_list_head;
59
60   /**
61    * DLL Resource
62    */
63   struct JsonApiResource *res_list_tail;
64
65   /**
66    * num resources
67    */
68   int res_count;
69 };
70
71 /**
72  * JSON API
73  */
74
75 /**
76  * Create a JSON API resource
77  *
78  * @param type the JSON API resource type
79  * @param id the JSON API resource id
80  * @return a new JSON API resource or NULL on error.
81  */
82 struct JsonApiResource*
83 GNUNET_REST_jsonapi_resource_new (const char *type, const char *id)
84 {
85   struct JsonApiResource *res;
86
87   if ( (NULL == type) || (0 == strlen (type)) )
88     return NULL;
89   if ( (NULL == id) || (0 == strlen (id)) )
90     return NULL;
91
92   res = GNUNET_new (struct JsonApiResource);
93   
94   res->res_obj = json_object ();
95
96   json_object_set_new (res->res_obj, GNUNET_REST_JSONAPI_KEY_ID, json_string (id));
97   json_object_set_new (res->res_obj, GNUNET_REST_JSONAPI_KEY_TYPE, json_string (type));
98
99   return res;
100 }
101
102 /**
103  * Delete a JSON API resource
104  *
105  * @param res the JSON resource
106  * @param result Pointer where the resource should be stored
107  */
108 void
109 GNUNET_REST_jsonapi_resource_delete (struct JsonApiResource *resource)
110 {
111   json_decref (resource->res_obj);
112   GNUNET_free (resource);
113 }
114
115 /**
116  * Add a JSON API attribute
117  *
118  * @param res the JSON resource
119  * @param key the key for the attribute
120  * @param json the json_t attribute to add
121  * @return #GNUNET_OK if added successfully
122  *         #GNUNET_SYSERR if not
123  */
124 int
125 GNUNET_REST_jsonapi_resource_add_attr (const struct JsonApiResource *resource,
126                                        const char* key,
127                                        json_t *json)
128 {
129   if ( (NULL == resource) ||
130        (NULL == key) ||
131        (NULL == json) )
132     return GNUNET_SYSERR;
133   json_object_set (resource->res_obj, key, json);
134   return GNUNET_OK;
135 }
136
137
138
139
140 /**
141  * Create a JSON API primary data
142  *
143  * @param type the JSON API resource type
144  * @param id the JSON API resource id
145  * @return a new JSON API resource or NULL on error.
146  */
147 struct JsonApiResponse*
148 GNUNET_REST_jsonapi_response_new ()
149 {
150   struct JsonApiResponse *result;
151
152   result = GNUNET_new (struct JsonApiResponse);
153   result->res_count = 0;
154   return result;
155 }
156
157 /**
158  * Delete a JSON API primary data
159  *
160  * @param type the JSON API resource type
161  * @param id the JSON API resource id
162  * @return a new JSON API resource or NULL on error.
163  */
164 void
165 GNUNET_REST_jsonapi_response_delete (struct JsonApiResponse *resp)
166 {
167   struct JsonApiResource *res;
168   
169   for (res = resp->res_list_head; 
170        res != NULL;
171        res = res->next)
172     GNUNET_REST_jsonapi_resource_delete (res);
173   GNUNET_free (resp);
174 }
175
176 /**
177  * Add a JSON API resource to primary data
178  *
179  * @param data The JSON API data to add to
180  * @param res the JSON API resource to add
181  * @return the new number of resources
182  */
183 void
184 GNUNET_REST_jsonapi_response_resource_add (struct JsonApiResponse *resp,
185                                            struct JsonApiResource *res)
186 {
187   GNUNET_CONTAINER_DLL_insert (resp->res_list_head,
188                             resp->res_list_tail,
189                             res);
190   
191   resp->res_count++;
192 }
193
194 /**
195  * Add a JSON API resource to primary data
196  *
197  * @param data The JSON API data to add to
198  * @param res the JSON API resource to add
199  * @return the new number of resources
200  */
201 void
202 GNUNET_REST_jsonapi_data_resource_remove (struct JsonApiResponse *resp,
203                                           struct JsonApiResource *res)
204 {
205   GNUNET_CONTAINER_DLL_remove (resp->res_list_head,
206                                resp->res_list_tail,
207                               res);
208   resp->res_count--;
209 }
210
211 /**
212  * String serialze jsonapi primary data
213  *
214  * @param data the JSON API primary data
215  * @param result where to store the result
216  * @return GNUNET_SYSERR on error else GNUNET_OK
217  */
218 int
219 GNUNET_REST_jsonapi_data_serialize (const struct JsonApiResponse *resp,
220                                     char **result)
221 {
222   struct JsonApiResource *res;
223   json_t *root_json;
224   json_t *res_arr;
225   
226   if ( (NULL == resp) ||
227        (0 == resp->res_count) )
228     return GNUNET_SYSERR;
229
230   root_json = json_object ();
231   
232   if (1 == resp->res_count)
233   {
234     json_object_set (root_json, GNUNET_REST_JSONAPI_KEY_DATA, resp->res_list_head->res_obj);
235   }
236   else
237   {
238     res_arr = json_array ();
239     for (res = resp->res_list_head; 
240          res != NULL;
241          res = res->next)
242     {
243       json_array_append (res_arr, res->res_obj);
244     }
245     json_object_set (root_json, GNUNET_REST_JSONAPI_KEY_DATA, res_arr);
246   }
247   *result = json_dumps (root_json, JSON_COMPACT);
248   return GNUNET_OK;
249 }
250
251 /**
252  * REST Utilities
253  */
254
255 /**
256  * Check if namespace is in URL.
257  *
258  * @param url URL to check
259  * @param namespace namespace to check against
260  * @retun GNUNET_YES if namespace matches
261  */
262 int
263 GNUNET_REST_namespace_match (const char *url, const char *namespace)
264 {
265   if (0 != strncmp (namespace, url, strlen (namespace)))
266     return GNUNET_NO;
267
268   if ((strlen (namespace) < strlen (url)) &&
269       (url[strlen (namespace)] != '/'))
270     return GNUNET_NO;
271
272   return GNUNET_YES;
273 }
274
275 /**
276  * Create JSON API MHD response
277  *
278  * @param data JSON result
279  * @retun MHD response
280  */
281  struct MHD_Response*
282 GNUNET_REST_create_json_response (const char *data)
283 {
284   struct MHD_Response *resp;
285   size_t len;
286
287   if (NULL == data)
288     len = 0;
289   else
290     len = strlen (data);
291   resp = MHD_create_response_from_buffer (len,
292                                           (void*)data,
293                                           MHD_RESPMEM_MUST_COPY);
294   MHD_add_response_header (resp,MHD_HTTP_HEADER_CONTENT_TYPE,"application/json");
295   return resp;
296
297 }
298
299 /* end of rest.c */