QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsserverogcapi.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsserverogcapi.cpp - 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 
17 #include <QDir>
18 #include <QDebug>
19 #include <QtGlobal>
20 
21 #include "qgsserverogcapi.h"
22 #include "qgsserverogcapihandler.h"
23 #include "qgsmessagelog.h"
24 #include "qgsapplication.h"
25 
26 QMap<QgsServerOgcApi::ContentType, QStringList> QgsServerOgcApi::sContentTypeMime = [ ]() -> QMap<QgsServerOgcApi::ContentType, QStringList>
27 {
28  QMap<QgsServerOgcApi::ContentType, QStringList> map;
29  map[QgsServerOgcApi::ContentType::JSON] = QStringList { QStringLiteral( "application/json" ) };
30  map[QgsServerOgcApi::ContentType::GEOJSON] = QStringList {
31  QStringLiteral( "application/geo+json" ),
32  QStringLiteral( "application/vnd.geo+json" ),
33  QStringLiteral( "application/geojson" )
34  };
35  map[QgsServerOgcApi::ContentType::HTML] = QStringList { QStringLiteral( "text/html" ) };
36  map[QgsServerOgcApi::ContentType::OPENAPI3] = QStringList { QStringLiteral( "application/vnd.oai.openapi+json;version=3.0" ) };
37  map[QgsServerOgcApi::ContentType::XML] = QStringList { QStringLiteral( "application/xml" ) };
38  return map;
39 }();
40 
41 QHash<QgsServerOgcApi::ContentType, QList<QgsServerOgcApi::ContentType>> QgsServerOgcApi::sContentTypeAliases = [ ]() -> QHash<ContentType, QList<ContentType>>
42 {
43  QHash<QgsServerOgcApi::ContentType, QList<QgsServerOgcApi::ContentType>> map;
44  map[ContentType::JSON] = { QgsServerOgcApi::ContentType::GEOJSON, QgsServerOgcApi::ContentType::OPENAPI3 };
45  return map;
46 }();
47 
48 
49 QgsServerOgcApi::QgsServerOgcApi( QgsServerInterface *serverIface, const QString &rootPath, const QString &name, const QString &description, const QString &version ):
50  QgsServerApi( serverIface ),
51  mRootPath( rootPath ),
52  mName( name ),
53  mDescription( description ),
54  mVersion( version )
55 {
56 
57 }
58 
60 {
61  //qDebug() << "API destroyed: " << name();
62 }
63 
65 {
66  std::shared_ptr<QgsServerOgcApiHandler> hp( handler );
67  mHandlers.emplace_back( std::move( hp ) );
68 }
69 
70 QUrl QgsServerOgcApi::sanitizeUrl( const QUrl &url )
71 {
72  // Since QT 5.12 NormalizePathSegments does not collapse double slashes
73  QUrl u { url.adjusted( QUrl::StripTrailingSlash | QUrl::NormalizePathSegments ) };
74  if ( u.path().contains( QLatin1String( "//" ) ) )
75  {
76  u.setPath( u.path().replace( QLatin1String( "//" ), QChar( '/' ) ) );
77  }
78  return u;
79 }
80 
82 {
83  // Get url
84  auto path { sanitizeUrl( context.request()->url() ).path() };
85  // Find matching handler
86  auto hasMatch { false };
87  for ( const auto &h : mHandlers )
88  {
89  QgsMessageLog::logMessage( QStringLiteral( "Checking API path %1 for %2 " ).arg( path, h->path().pattern() ), QStringLiteral( "Server" ), Qgis::Info );
90  if ( h->path().match( path ).hasMatch() )
91  {
92  hasMatch = true;
93  // Execute handler
94  QgsMessageLog::logMessage( QStringLiteral( "API %1: found handler %2" ).arg( name(), QString::fromStdString( h->operationId() ) ), QStringLiteral( "Server" ), Qgis::Info );
95  // May throw QgsServerApiBadRequestException or JSON exceptions on serializing
96  try
97  {
98  h->handleRequest( context );
99  }
100  catch ( json::exception &ex )
101  {
102  throw QgsServerApiInternalServerError( QStringLiteral( "The API handler returned an error: %1" ).arg( ex.what() ) );
103  }
104  break;
105  }
106  }
107  // Throw
108  if ( ! hasMatch )
109  {
110  throw QgsServerApiBadRequestException( QStringLiteral( "Requested URI does not match any registered API handler" ) );
111  }
112 }
113 
114 const QMap<QgsServerOgcApi::ContentType, QStringList> QgsServerOgcApi::contentTypeMimes()
115 {
116  return sContentTypeMime;
117 }
118 
119 const QHash<QgsServerOgcApi::ContentType, QList<QgsServerOgcApi::ContentType> > QgsServerOgcApi::contentTypeAliases()
120 {
121  return sContentTypeAliases;
122 }
123 
124 std::string QgsServerOgcApi::relToString( const Rel &rel )
125 {
126  static QMetaEnum metaEnum = QMetaEnum::fromType<QgsServerOgcApi::Rel>();
127  std::string val { metaEnum.valueToKey( rel ) };
128  std::replace( val.begin(), val.end(), '_', '-' );
129  return val;
130 }
131 
133 {
134  static QMetaEnum metaEnum = QMetaEnum::fromType<ContentType>();
135  QString result { metaEnum.valueToKey( ct ) };
136  return result.replace( '_', '-' );
137 }
138 
140 {
141  static QMetaEnum metaEnum = QMetaEnum::fromType<ContentType>();
142  return metaEnum.valueToKey( ct );
143 }
144 
146 {
147  return contentTypeToString( ct ).toLower();
148 }
149 
151 {
152  const QString exts = QString::fromStdString( extension );
153  for ( auto it = QgsServerOgcApi::contentTypeMimes().constBegin();
154  it != QgsServerOgcApi::contentTypeMimes().constEnd();
155  ++it )
156  {
157  const auto constValues = it.value();
158  for ( const auto &value : constValues )
159  {
160  if ( value.contains( exts, Qt::CaseSensitivity::CaseInsensitive ) )
161  {
162  return it.key();
163  }
164  }
165  }
166  // Default to JSON, but log a warning!
167  QgsMessageLog::logMessage( QStringLiteral( "Content type for extension %1 not found! Returning default (JSON)" ).arg( exts ),
168  QStringLiteral( "Server" ),
169  Qgis::Warning );
170  return QgsServerOgcApi::ContentType::JSON;
171 }
172 
174 {
175  if ( ! sContentTypeMime.contains( contentType ) )
176  {
177  return "";
178  }
179  return sContentTypeMime.value( contentType ).first().toStdString();
180 }
181 
182 const std::vector<std::shared_ptr<QgsServerOgcApiHandler> > QgsServerOgcApi::handlers() const
183 {
184  return mHandlers;
185 }
186 
187 
QgsServerApiContext
The QgsServerApiContext class encapsulates the resources for a particular client request: the request...
Definition: qgsserverapicontext.h:39
QgsServerOgcApi::relToString
static std::string relToString(const QgsServerOgcApi::Rel &rel)
Returns the string representation of rel attribute.
Definition: qgsserverogcapi.cpp:124
Qgis::Warning
@ Warning
Definition: qgis.h:91
QgsServerOgcApi::name
const QString name() const override
Returns the API name.
Definition: qgsserverogcapi.h:104
QgsServerApiInternalServerError
Internal server error API exception.
Definition: qgsserverexception.h:203
QgsServerOgcApi::sanitizeUrl
static QUrl sanitizeUrl(const QUrl &url)
Returns a sanitized url with extra slashes removed.
Definition: qgsserverogcapi.cpp:70
QgsServerOgcApi::contentTypeMimes
static const QMap< QgsServerOgcApi::ContentType, QStringList > contentTypeMimes()
Returns a map of contentType => list of mime types.
Definition: qgsserverogcapi.cpp:114
QgsServerOgcApi::registerHandler
void registerHandler(Args... args)
Registers an OGC API handler passing Args to the constructor.
Definition: qgsserverogcapi.h:136
QgsServerOgcApi::contentTypeToExtension
static QString contentTypeToExtension(const QgsServerOgcApi::ContentType &ct)
Returns the file extension for a ct (Content-Type).
Definition: qgsserverogcapi.cpp:145
qgsapplication.h
Qgis::Info
@ Info
Definition: qgis.h:90
QgsServerOgcApi::QgsServerOgcApi
QgsServerOgcApi(QgsServerInterface *serverIface, const QString &rootPath, const QString &name, const QString &description=QString(), const QString &version=QString())
QgsServerOgcApi constructor.
Definition: qgsserverogcapi.cpp:49
qgsserverogcapihandler.h
QgsServerOgcApi::handlers
const std::vector< std::shared_ptr< QgsServerOgcApiHandler > > handlers() const
Returns registered handlers.
Definition: qgsserverogcapi.cpp:182
QgsServerOgcApi::contentTypeAliases
static const QHash< QgsServerOgcApi::ContentType, QList< QgsServerOgcApi::ContentType > > contentTypeAliases()
Returns contentType specializations (e.g.
Definition: qgsserverogcapi.cpp:119
qgsserverogcapi.h
QgsServerOgcApi::Rel
Rel
Rel link types.
Definition: qgsserverogcapi.h:58
QgsServerOgcApiHandler
The QgsServerOgcApiHandler abstract class represents a OGC API handler to be registered in QgsServerO...
Definition: qgsserverogcapihandler.h:95
QgsServerOgcApi::executeRequest
virtual void executeRequest(const QgsServerApiContext &context) const override SIP_THROW(QgsServerApiBadRequestException)
Executes a request by passing the given context to the API handlers.
Definition: qgsserverogcapi.cpp:81
QgsServerOgcApi::contentTypeToString
static QString contentTypeToString(const QgsServerOgcApi::ContentType &ct)
Returns the string representation of a ct (Content-Type) attribute.
Definition: qgsserverogcapi.cpp:132
QgsServerOgcApi::contenTypeFromExtension
static QgsServerOgcApi::ContentType contenTypeFromExtension(const std::string &extension)
Returns the Content-Type value corresponding to extension.
Definition: qgsserverogcapi.cpp:150
QgsServerOgcApi::~QgsServerOgcApi
~QgsServerOgcApi() override
Definition: qgsserverogcapi.cpp:59
QgsServerOgcApi::mimeType
static std::string mimeType(const QgsServerOgcApi::ContentType &contentType)
Returns the mime-type for the contentType or an empty string if not found.
Definition: qgsserverogcapi.cpp:173
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
QgsServerRequest::url
QUrl url() const
Definition: qgsserverrequest.cpp:65
QgsServerApiContext::request
const QgsServerRequest * request() const
Returns the server request object.
Definition: qgsserverapicontext.cpp:33
QgsServerApi
Server generic API endpoint abstract base class.
Definition: qgsserverapi.h:81
QgsServerOgcApi::ContentType
ContentType
Media types used for content negotiation, insert more specific first.
Definition: qgsserverogcapi.h:80
QgsServerApiBadRequestException
Bad request error API exception.
Definition: qgsserverexception.h:245
QgsServerInterface
QgsServerInterface Class defining interfaces exposed by QGIS Server and made available to plugins.
Definition: qgsserverinterface.h:61
QgsServerOgcApi::contentTypeToStdString
static std::string contentTypeToStdString(const QgsServerOgcApi::ContentType &ct)
Returns the string representation of a ct (Content-Type) attribute.
Definition: qgsserverogcapi.cpp:139
qgsmessagelog.h