.. _services/rest_api: API di Genropy ============== Genropy mette a disposizione un sistema di comunicazione per ricevere informazioni dall'esterno tramite chiamate REST. Le API di Genropy possono essere utilizzate per modificare inserire, modificare o eliminare record, per esempio per disiscrivere un utente da una mailing list, o aggiungere un indirizzo e-mail alla lista dei contatti, o ancora modificare le quantità di un prodotto a magazzino, innescare script, ecc. Le API di Genropy prevedono innanzitutto la definizione, in una *webpage*, di un **webhook**, ovvero un metodo che, una volta "attivato" da chiamate *POST/GET* da un service esterno, permetterà di eseguire le azioni desiderate. Il primo passo è quindi la definizione all'interno di un package di una webpage con il metodo desiderato:: from gnr.core.gnrdecorator import public_method class GnrCustomWebPage(object): py_requires = 'gnrcomponents/externalcall:BaseRpc' @public_method def metodo_webhook(self, **kwargs): pass Il *metodo_webhook* non dovrà necessariamente chiamarsi così ma potrà essere nominato a piacimento. Si noti che il nome del metodo webhook determinerà l'URL da chiamare, ad esempio:: https://dominiogenropy.it/nome_package/nome_webpage/metodo_webhook Si noti che il metodo deve prevedere l'utilizzo del decoratore ``@public_method``. I parametri possono essere passati in modo esplicito (es: *contatto_id=None*), oppure nei ** *kwargs*. Il webhook invocato elaborerà un oggetto ``self.request`` e un oggetto ``self.response``. È infatti possibile fornire risposte di tipo differente, o innescare azioni diverse a seconda del tipo di chiamata GET o POST, ad esempio:: if self.request.method == 'GET': if kwargs['verify_token'] == token: return kwargs['challenge'] else: self.response.status_code = 403 return 'Access forbidden' elif request.method == 'POST': incoming_message = json.loads(request.data.decode('utf-8')) self.recordFromMessage(incoming_message=incoming_message) Nell'esempio distinguiamo innanzitutto se la chiamata che abbiamo ricevuto (*self.request.method*) è di tipo ``GET`` o di tipo ``POST``. Se è di tipo *GET*, controlliamo che contenga un token corrispondente a una variabile *token* che avremo definito in altra sede: se corrisponde, restituiamo un ulteriore parametro *challenge* che ci sarà stato fornito nella chiamata, alternativamente restituiamo un codice di errore 403. Se invece è di tipo *POST*, elaboriamo il messaggio in ingresso e lanciamo un altro metodo *recordFromMessage*. .. hint:: Si noti che di default lo *status_code* della risposta sarà sempre ``200 OK`` salvo diversamente specificato. Si consiglia sempre di **inviare un token prima di effettuare modifiche al database**. Nel caso precedente abbiamo inviato il token come semplice parametro (``verify_token``), sfruttando poi il codice della risposta per "bloccare" la procedura, ma in alternativa possiamo fare lo stesso tipo di controllo nell'*header* della chiamata, interrompendo il flusso se l'autorizzazione non viene correttamente verificata:: app_token = self.site.getPreference('subscription_token', pkg='dem') received_token = self.request.headers.get('Authorization') if f'Bearer {app_token}' != received_token: raise GnrBasicAuthenticationError('Wrong Authorization Login') .. sectionauthor:: Davide Paci