1 /*************************************************************************** 2 qgsserverogcapi.h - QgsServerOgcApi 3 4 --------------------- 5 begin : 10.7.2019 6 copyright : (C) 2019 by Alessandro Pasotti 7 email : elpaso at itopen dot it 8 *************************************************************************** 9 * * 10 * This program is free software; you can redistribute it and/or modify * 11 * it under the terms of the GNU General Public License as published by * 12 * the Free Software Foundation; either version 2 of the License, or * 13 * (at your option) any later version. * 14 * * 15 ***************************************************************************/ 16 #ifndef QGSSERVEROGCAPI_H 17 #define QGSSERVEROGCAPI_H 18 19 #include "qgsserverapi.h" 20 #include "qgis_server.h" 21 22 23 class QgsServerOgcApiHandler; 24 25 /** 26 * \ingroup server 27 * \brief QGIS Server OGC API endpoint. QgsServerOgcApi provides the foundation for 28 * the new generation of REST-API based OGC services (e.g. WFS3). 29 * 30 * This class can be used directly and configured by registering handlers 31 * as instances of QgsServerOgcApiHandler. 32 * 33 * \code{.py} 34 * 35 * class Handler1(QgsServerOgcApiHandler): 36 * """A handler, see QgsServerOgcApiHandler for an example""" 37 * ... 38 * 39 * h = Handler1() 40 * api = QgsServerOgcApi(serverInterface(), "/api1", "apione", "A firs API", "1.0") 41 * api.registerHandler(h) 42 * server.serverInterface().serviceRegistry().registerApi(api) 43 * 44 * \endcode 45 * 46 * \since QGIS 3.10 47 */ 48 class SERVER_EXPORT QgsServerOgcApi : public QgsServerApi 49 { 50 51 Q_GADGET 52 53 public: 54 55 // Note: non a scoped enum or qHash fails 56 //! Rel link types 57 enum Rel 58 { 59 // The following registered link relation types are used 60 alternate, //! Refers to a substitute for this context. 61 describedBy, //! Refers to a resource providing information about the link’s context. 62 collection, //! The target IRI points to a resource that is a member of the collection represented by the context IRI. 63 item, //! The target IRI points to a resource that is a member of the collection represented by the context IRI. 64 self, //! Conveys an identifier for the link’s context. 65 service_desc, //! Identifies service description for the context that is primarily intended for consumption by machines. 66 service_doc, //! Identifies service documentation for the context that is primarily intended for human consumption. 67 prev, //! Indicates that the link’s context is a part of a series, and that the previous in the series is the link targe 68 next, //! Indicates that the link’s context is a part of a series, and that the next in the series is the link target. 69 license, //! Refers to a license associated with this context. 70 // In addition the following link relation types are used for which no applicable registered link relation type could be identified: 71 items, //! Refers to a resource that is comprised of members of the collection represented by the link’s context. 72 conformance, //! The target IRI points to a resource which represents the collection resource for the context IRI. 73 data //! The target IRI points to resource data 74 }; 75 Q_ENUM( Rel ) 76 77 // Note: cannot be a scoped enum because qHash does not support them 78 //! Media types used for content negotiation, insert more specific first 79 enum ContentType 80 { 81 GEOJSON, 82 OPENAPI3, //! "application/openapi+json;version=3.0" 83 JSON, 84 HTML, 85 XML 86 }; 87 Q_ENUM( ContentType ) 88 89 /** 90 * QgsServerOgcApi constructor 91 * \param serverIface pointer to the server interface 92 * \param rootPath root path for this API (usually starts with a "/", e.g. "/wfs3") 93 * \param name API name 94 * \param description API description 95 * \param version API version 96 */ 97 QgsServerOgcApi( QgsServerInterface *serverIface, 98 const QString &rootPath, 99 const QString &name, 100 const QString &description = QString(), 101 const QString &version = QString() ); 102 103 // QgsServerApi interface name()104 const QString name() const override { return mName; } description()105 const QString description() const override { return mDescription; } version()106 const QString version() const override { return mVersion; } rootPath()107 const QString rootPath() const override { return mRootPath ; } 108 109 ~QgsServerOgcApi() override; 110 111 /** 112 * Executes a request by passing the given \a context to the API handlers. 113 */ 114 virtual void executeRequest( const QgsServerApiContext &context ) const override SIP_THROW( QgsServerApiBadRequestException ) SIP_VIRTUALERRORHANDLER( serverapi_badrequest_exception_handler ); 115 116 /** 117 * Returns a map of contentType => list of mime types 118 * \note not available in Python bindings 119 */ 120 static const QMap<QgsServerOgcApi::ContentType, QStringList> contentTypeMimes() SIP_SKIP; 121 122 /** 123 * Returns contentType specializations (e.g. JSON => [GEOJSON, OPENAPI3], XML => [GML]) 124 * \note not available in Python bindings 125 */ 126 static const QHash<QgsServerOgcApi::ContentType, QList<QgsServerOgcApi::ContentType> > contentTypeAliases() SIP_SKIP; 127 128 // Utilities 129 #ifndef SIP_RUN 130 131 /** 132 * Registers an OGC API handler passing \a Args to the constructor 133 * \note not available in Python bindings 134 */ 135 template<class T, typename... Args> registerHandler(Args...args)136 void registerHandler( Args... args ) 137 { 138 mHandlers.emplace_back( std::make_shared<T>( args... ) ); 139 } 140 #endif 141 142 /** 143 * Registers an OGC API \a handler, ownership of the handler is transferred to the API 144 */ 145 void registerHandler( QgsServerOgcApiHandler *handler SIP_TRANSFER ); 146 147 /** 148 * Returns a sanitized \a url with extra slashes removed and the path URL component that 149 * always starts with a slash. 150 */ 151 static QUrl sanitizeUrl( const QUrl &url ); 152 153 /** 154 * Returns the string representation of \a rel attribute. 155 */ 156 static std::string relToString( const QgsServerOgcApi::Rel &rel ); 157 158 /** 159 * Returns the string representation of a \a ct (Content-Type) attribute. 160 */ 161 static QString contentTypeToString( const QgsServerOgcApi::ContentType &ct ); 162 163 /** 164 * Returns the string representation of a \a ct (Content-Type) attribute. 165 */ 166 static std::string contentTypeToStdString( const QgsServerOgcApi::ContentType &ct ); 167 168 /** 169 * Returns the file extension for a \a ct (Content-Type). 170 */ 171 static QString contentTypeToExtension( const QgsServerOgcApi::ContentType &ct ); 172 173 /** 174 * Returns the Content-Type value corresponding to \a extension. 175 */ 176 static QgsServerOgcApi::ContentType contenTypeFromExtension( const std::string &extension ); 177 178 /** 179 * Returns the mime-type for the \a contentType or an empty string if not found 180 */ 181 static std::string mimeType( const QgsServerOgcApi::ContentType &contentType ); 182 183 /** 184 * Returns registered handlers 185 */ 186 const std::vector<std::shared_ptr<QgsServerOgcApiHandler> > handlers() const SIP_SKIP; 187 188 private: 189 190 QString mRootPath; 191 QString mName; 192 QString mDescription; 193 QString mVersion; 194 195 //Note: this cannot be unique because of SIP bindings 196 std::vector<std::shared_ptr<QgsServerOgcApiHandler>> mHandlers; 197 198 //! For each content type, stores a list of at least one content type mime strings aliases 199 static QMap<QgsServerOgcApi::ContentType, QStringList> sContentTypeMime; 200 201 /** 202 * Stores content type generalization aliases (e.g. JSON->[GEOJSON,OPENAPI3], XML->[GML] ) 203 * We are good citizen and we accept JSON from the client (for example) if the actual type 204 * is a JSON-based format (OPENAPI3 or GEOJSON). 205 */ 206 static QHash<QgsServerOgcApi::ContentType, QList<QgsServerOgcApi::ContentType>> sContentTypeAliases; 207 208 }; 209 210 #endif // QGSSERVEROGCAPI_H 211