UNPKG

geoportal-access-lib

Version:

French Geoportal resources access library

468 lines (421 loc) 19.2 kB
import Logger from "../Utils/LoggerByDefault"; import Helper from "../Utils/Helper"; import _ from "../Utils/MessagesResources"; import Protocol from "../Protocols/Protocol"; import ErrorService from "../Exceptions/ErrorService"; // import DefaultUrlService from "./DefaultUrlService"; // package.json (extract version) import Pkg from "../../package.json"; /** * @classdesc * Composant Service * * @constructor * @alias Gp.Services.CommonService * @param {Object} options - options communes à tous les services * * @param {String} [options.serverUrl] - URL d'accès au service. Par défaut "https://data.geopf.fr/SERVICE/". * Permet de forcer l'utilisation d'un service équivalent déployé derrière une éventuelle autre URL d'accès. * Si ce paramètre est renseigné alors, le paramètre par défaut est ignoré. * * @param {String} [options.protocol] - Le protocole à utiliser pour récupérer les informations du service : * peut valoir 'JSONP' ou 'XHR'. * Par défaut, c'est le protocole XHR qui sera utilisé. * Attention, le protocole JSONP n'est pas valide dans un environnement NodeJS (Utilisation du mode XHR). * * @param {Boolean} [options.ssl] - Indique si l'on souhaite intérroger les services en https. * Ce paramètre ne fonctionne que pour une utilisation hors navigateur (ex. NodeJS). * Sur un navigateur, le protocole est automatiquement extrait de l'url du site... * Par défaut, on utilise le protocole http (ssl=false). * * @param {String} [options.proxyURL] - Le proxy à utiliser pour pallier au problème de cross-domain dans le cas d'une requête XHR. * Utile si le paramètre 'protocol' vaut 'XHR', il ne sera pas pris en compte si protocol vaut JSONP. * * @param {String} [options.callbackSuffix] - Suffixe de la fonction de callback à utiliser, dans le cas du protocole JSONP. * Par défaut, la fonction de callback portera un nom du type "callback"+ID, où ID est soit un identifiant unique généré à chaque requête, * soit le paramètre callbackSuffix s'il est spécifié. Par exemple, si callbackSuffix="_2", la fonction sera "callback_2 ()". * Utile pour utiliser une réponse déjà encapsulée dans une fonction de callback, dont le nom est connu * Utile seulement si le paramètre 'protocol' vaut 'JSONP', il ne sera pas pris en compte si protocol vaut 'XHR'. * * @param {String} [options.httpMethod] - La méthode HTTP * à utiliser dans le cas d'une requête XHR : peut valoir 'GET' ou 'POST'. * Non pris en compte si 'protocol' vaut JSONP qui fonctionne obligatoirement en GET. * Par défaut, c'est la méthode GET qui est utilisée. * * @param {String} [options.contentType] - Content-Type de la requete * à utiliser dans le cas d'une requête XHR en mode POST. * Non pris en compte si 'protocol' vaut JSONP et/ou la méthode HTTP vaut GET. * Par défaut, c'est la méthode GET qui est utilisée donc on n'utilise pas de Content-Type. * * @param {Number} [options.timeOut] - Délai d'attente maximal (en ms) de la réponse du service (à partir de l'envoi de la requête). * Par défaut, aucun timeOut n'est pris en compte (timeoutDelay= 0). * * @param {Boolean} [options.rawResponse] - Indique si l'on souhaite que la réponse du service ne soit pas parsée par l'API avant d'être restituée. * (Cf. paramètre « onSuccess » pour plus de détails). * * @param {Function} [options.onSuccess] - Fonction appelée lorsque le service répond correctement à la requête * (code HTTP 200, sans message d'erreur). * Cette fonction prend en paramètre la réponse du service, * soit sous la forme d'un Object Javascript formaté par le parseur dédié à la syntaxe du service (comportement par défaut) ; * soit brute au format String non prétraité si le paramètre « rawResponse » a été précisé avec la valeur « true ». * * @param {Function} [options.onFailure] - Fonction appelée lorsque le service ne répond pas correctement * (code HTTP de retour différent de 200 ou pas de réponse). * * @param {Function} [options.onBeforeParse] - Fonction appelée avant le parsing de la réponse * Permet de modifier la réponse avant parsing et la fonction doit retourner une String. * Cette fonction prend en paramètre la réponse telle que renvoyée par le service * (cad au format json ou xml). * Pour le JSONP, si le paramètre "rawResponse" a été précisé avec la valeur "true", * la fonction prend en paramètre un Object JavaScript contenant la réponse XML. * * @example * var options = { * serverUrl : 'http://localhost/service/', * protocol : 'JSONP', // JSONP|XHR * ssl : false, * proxyURL : null, * callbackName : null, * httpMethod : 'GET', // GET|POST * timeOut : 10000, // ms * rawResponse : false, // true|false * scope : null, // this * onSuccess : function (response) {}, * onFailure : function (error) {}, * onBeforeParse : function (rawResponse) {} * }; */ function CommonService (options) { if (!(this instanceof CommonService)) { throw new TypeError(_.getMessage("CLASS_CONSTRUCTOR")); } this.logger = Logger.getLogger("CommonService"); this.logger.trace("[Constructeur CommonService (options)]"); // ##################### // récupération des options par défaut pour les paramètres optionnels // ##################### /** * Options du service * @type {Object} */ this.options = { // protocol : "JSONP", protocol : "XHR", ssl : true, proxyURL : "", // callbackName : "", callbackSuffix : null, httpMethod : "GET", timeOut : 0, rawResponse : false, scope : this, /** * callback par defaut pour la reponse * @param {Object} response - response * @private */ onSuccess : function (response) { console.log("onSuccess - la reponse est la suivante : ", response); }, /** * callback par defaut pour les erreurs * @param {Object} error - error * @private */ onFailure : function (error) { if (error.status === 200 || !error.status) { console.log("onFailure : ", error.message); } else { console.log("onFailure - Erreur (", error.status, ") : ", error.message); } } }; // et on ajoute les options en paramètre aux options par défaut for (var opt in options) { if (options.hasOwnProperty(opt)) { this.options[opt] = options[opt]; } } // ##################### // analyse des options // ##################### // modification de la fonction de callback onSuccess dans le cas où la réponse brute est demandée if (this.options.rawResponse && !this.options.onSuccess) { /** * callback par defaut pour la reponse * @param {Object} response - response * @private */ this.options.onSuccess = function (response) { console.log("onSuccess - la réponse brute du service est la suivante : ", response); }; } // gestion du callback onSuccess var bOnSuccess = !!(this.options.onSuccess !== null && typeof this.options.onSuccess === "function"); if (!bOnSuccess) { throw new Error(_.getMessage("PARAM_MISSING", "onSuccess()")); } // gestion de la methode HTTP this.options.httpMethod = (typeof options.httpMethod === "string") ? options.httpMethod.toUpperCase() : "GET"; switch (this.options.httpMethod) { case "POST": case "GET": break; case "PUT": case "DELETE": case "HEAD": case "OPTIONS": throw new Error(_.getMessage("PARAM_NOT_SUPPORT", "httpMethod")); default: throw new Error(_.getMessage("PARAM_UNKNOWN", "httpMethod")); } // gestion du protocole // this.options.protocol = (typeof options.protocol === "string" ) ? options.protocol.toUpperCase() : "JSONP"; this.options.protocol = (typeof options.protocol === "string") ? options.protocol.toUpperCase() : "XHR"; switch (this.options.protocol) { case "JSONP": case "XHR": break; default: throw new Error(_.getMessage("PARAM_UNKNOWN", "protocol")); } // on determine l'environnement d'execution : browser ou non ? // et on lance une exception sur l'utilisation du protocole JSONP pour nodeJS... if (typeof window === "undefined" && this.options.protocol === "JSONP") { throw new Error(_.getMessage("PARAM_NOT_SUPPORT_NODEJS", "protocol=JSONP (instead use XHR)")); } // le protocole JSONP ne fonctionne qu'en GET. if (this.options.protocol === "JSONP") { this.options.httpMethod = "GET"; } // gestion du cache this.options.nocache = options.nocache || false; // ##################### // attributs d'instances // ##################### /** * Format de réponse du service */ this.options.outputFormat = null; /** * Requête envoyée au service */ this.request = null; /** * Reponse du service */ this.response = null; } /** * @lends module:CommonService */ CommonService.prototype = { /* * Constructeur (alias) */ constructor : CommonService, /** * Appel du service Géoportail */ call : function () { /* jshint validthis : true */ this.logger.trace("CommonService::call ()"); var context = this; /** fonction d'execution */ function run () { this.logger.trace("CommonService::run ()"); this.buildRequest.call(context, onError, onBuildRequest); } run.call(context); // callback de fin de construction de la requête function onBuildRequest (result) { this.logger.trace("CommonService::onBuildRequest : ", result); this.callService.call(context, onError, onCallService); } // callback de fin d'appel au service function onCallService (result) { this.logger.trace("CommonService::onCallService : ", result); this.analyzeResponse.call(context, onError, onAnalyzeResponse); } // callback de fin de lecture de la reponse function onAnalyzeResponse (result) { this.logger.trace("CommonService::onAnalyzeResponse : ", result); if (result) { this.options.onSuccess.call(this, result); } else { return onError.call(this, new ErrorService("Analyse de la reponse en échec !?")); } } // callback de gestion des erreurs : renvoit un objet de type ErrorService function onError (error) { this.logger.trace("CommonService::onError()"); // error : l'objet est du type ErrorService ou Error var e = error; if (!(e instanceof ErrorService)) { e = new ErrorService(error.message); } this.options.onFailure.call(this, e); } }, /** * Création de la requête * @param {Function} error - callback * @param {Function} success - callback */ buildRequest : function (error, success) { // INFO this.logger.error("overwritten method !"); // retourne l'objet 'this.request' if (error) { error.call(this, "This method must be overwritten !"); } success.call(this, "This method must be overwritten !"); }, /** * Appel du service * @param {Function} error - callback * @param {Function} success - callback */ callService : function (error, success) { // INFO // retourne l'objet 'this.response' // NOTES // Pour le mode XHR, on recupère une reponse sous forme d'un json ou xml (#document). // Pour le mode JSONP, on a toujours un objet JSON mais sous 2 formes : // - natif // - XML encapsulé : // {http : {status:200, error:null},xml :'réponse du service'} // {http : {status:400, error:'reponse du service'},xml :null} // En XHR, la reponse est directement sauvegardée dans 'this.response'. // Par contre, en JSONP, on doit analyser la reponse (status ou non vide), // et ne renvoyer que le contenu (xml ou l'objet) // gestion de la proxification du service var strUrlProxified = null; var strData = this.request; // a t on mis en place un proxy ? // la proxyfication est valable uniquement en mode XHR ! var bUrlProxified = !!(this.options.proxyURL && this.options.protocol === "XHR"); // rajout de l'option gpbibaccess // INFO : acces au numero de version de package.conf aprés compilation ! var requestMetaOptions = { "gp-access-lib" : Pkg.version }; if (this.options.apiKey) { requestMetaOptions.apiKey = this.options.apiKey; } this.options.serverUrl = Helper.normalyzeUrl(this.options.serverUrl, requestMetaOptions, false); // si le proxy est renseigné, on proxifie l'url du service if (bUrlProxified) { if (this.options.httpMethod === "GET") { strUrlProxified = this.options.proxyURL + Helper.normalyzeUrl(this.options.serverUrl, this.request, true); strData = null; } if (this.options.httpMethod === "POST") { strUrlProxified = this.options.proxyURL + Helper.normalyzeUrl(this.options.serverUrl, null, true); strData = this.request; } } // contexte du composant spécifique ! var self = this; var options = { url : strUrlProxified || this.options.serverUrl, method : this.options.httpMethod, protocol : this.options.protocol, timeOut : this.options.timeOut || 0, format : this.options.outputFormat, // ceci declenche le parsing de la reponse du service, mais on souhaite toujours une reponse brute (string) ! nocache : this.options.nocache || false, // ceci permet d'ajouter un timestamp dans la requête wrap : this.options.protocol !== "XHR", // ceci declenche l'encapsulation de la reponse XML du service dans du JSON, mais pas en mode XHR ! callbackSuffix : this.options.callbackSuffix, // callbackName : this.options.callbackName || null, data : strData, headers : null, // TODO... content : this.options.contentType || "application/xml", scope : this.options.scope || this, // callback de reponse onResponse : function (response) { self.logger.trace("callService::onResponse()"); // le contenu de la reponse à renvoyer ! var content = null; // XHR : on renvoie toujours la reponse brute du service (json ou xml) // au parser du composant... if (self.options.protocol === "XHR") { self.logger.trace("Response XHR", response); content = response; // par defaut, la reponse du service ! } // JSONP : on pre-analyse la reponse brute du service (encapsuler ou pas) // avant de l'envoyer au parser du composant... if (self.options.protocol === "JSONP") { self.logger.trace("Response JSON", response); if (response) { if (response.http) { // reponse encapsulée : // ex. reponse du service en xml // > {http : {status:200, error:null},xml :'réponse du service'} if (response.http.status !== 200) { error.call(self, new ErrorService({ status : response.http.status, message : response.http.error, type : ErrorService.TYPE_SRVERR })); return; } else { content = response.xml; // par defaut ! if (self.options.rawResponse) { content = response; } } } else { // reponse non encapsulée : // ex. reponse du service en json ou xml content = response; } } else { error.call(self, new ErrorService("Le contenu de la reponse est vide !?")); return; } } // si on souhaite parser la reponse du service if (typeof self.options.onBeforeParse === "function") { var newResponse = self.options.onBeforeParse(content); if (typeof newResponse === "string") { // la reponse parsée par l'utilisateur est retournée sous // forme de string ! content = newResponse; } } // sauvegarde de la reponse dans l'objet parent (CommonService) self.response = content; // on renvoie la reponse... success.call(self, content); }, // callback des erreurs onFailure : function (e) { self.logger.trace("callService::onFailure()"); // on est forcement sur une erreur levée par un service ! e.type = ErrorService.TYPE_SRVERR; error.call(self, new ErrorService(e)); }, // callback de timeOut onTimeOut : function () { self.logger.trace("callService::onTimeOut()"); error.call(self, new ErrorService("TimeOut!")); } }; Protocol.send(options); }, /** * Analyse de la réponse * @param {Function} error - callback * @param {Function} success - callback */ analyzeResponse : function (error, success) { // INFO this.logger.error("overwritten method !"); // retourne l'objet spécifique au type de composant (json) if (error) { error.call(this, "This method must be overwritten !"); } success.call(this, "This method must be overwritten !"); } }; export default CommonService;