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