QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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"
23#include "qgsmessagelog.h"
24#include "qgsapplication.h"
25
26QMap<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
41QHash<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
49QgsServerOgcApi::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
70QUrl 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 // Make sure the path starts with '/'
79 if ( !u.path().startsWith( '/' ) )
80 {
81 u.setPath( u.path().prepend( '/' ) );
82 }
83 return u;
84}
85
87{
88 // Get url
89 const auto path { sanitizeUrl( context.handlerPath( ) ).path() };
90 // Find matching handler
91 auto hasMatch { false };
92 for ( const auto &handler : mHandlers )
93 {
94 QgsMessageLog::logMessage( QStringLiteral( "Checking API path %1 for %2 " ).arg( path, handler->path().pattern() ), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
95 if ( handler->path().match( path ).hasMatch() )
96 {
97 hasMatch = true;
98 // Execute handler
99 QgsMessageLog::logMessage( QStringLiteral( "API %1: found handler %2" ).arg( name(), QString::fromStdString( handler->operationId() ) ), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
100 // May throw QgsServerApiBadRequestException or JSON exceptions on serializing
101 try
102 {
103 handler->handleRequest( context );
104 }
105 catch ( json::exception &ex )
106 {
107 throw QgsServerApiInternalServerError( QStringLiteral( "The API handler returned an error: %1" ).arg( ex.what() ) );
108 }
109 break;
110 }
111 }
112 // Throw
113 if ( ! hasMatch )
114 {
115 throw QgsServerApiBadRequestException( QStringLiteral( "Requested URI does not match any registered API handler" ) );
116 }
117}
118
119const QMap<QgsServerOgcApi::ContentType, QStringList> QgsServerOgcApi::contentTypeMimes()
120{
121 return sContentTypeMime;
122}
123
124const QHash<QgsServerOgcApi::ContentType, QList<QgsServerOgcApi::ContentType> > QgsServerOgcApi::contentTypeAliases()
125{
126 return sContentTypeAliases;
127}
128
129std::string QgsServerOgcApi::relToString( const Rel &rel )
130{
131 static const QMetaEnum metaEnum = QMetaEnum::fromType<QgsServerOgcApi::Rel>();
132 std::string val { metaEnum.valueToKey( rel ) };
133 std::replace( val.begin(), val.end(), '_', '-' );
134 return val;
135}
136
138{
139 static const QMetaEnum metaEnum = QMetaEnum::fromType<ContentType>();
140 QString result { metaEnum.valueToKey( ct ) };
141 return result.replace( '_', '-' );
142}
143
145{
146 static const QMetaEnum metaEnum = QMetaEnum::fromType<ContentType>();
147 return metaEnum.valueToKey( ct );
148}
149
151{
152 return contentTypeToString( ct ).toLower();
153}
154
156{
157 const QString exts = QString::fromStdString( extension );
158 const auto constMimeTypes( QgsServerOgcApi::contentTypeMimes() );
159 for ( auto it = constMimeTypes.constBegin();
160 it != constMimeTypes.constEnd();
161 ++it )
162 {
163 const auto constValues = it.value();
164 for ( const auto &value : constValues )
165 {
166 if ( value.contains( exts, Qt::CaseSensitivity::CaseInsensitive ) )
167 {
168 return it.key();
169 }
170 }
171 }
172 // Default to JSON, but log a warning!
173 QgsMessageLog::logMessage( QStringLiteral( "Content type for extension %1 not found! Returning default (JSON)" ).arg( exts ),
174 QStringLiteral( "Server" ),
175 Qgis::MessageLevel::Warning );
176 return QgsServerOgcApi::ContentType::JSON;
177}
178
180{
181 if ( ! sContentTypeMime.contains( contentType ) )
182 {
183 return "";
184 }
185 return sContentTypeMime.value( contentType ).first().toStdString();
186}
187
188const std::vector<std::shared_ptr<QgsServerOgcApiHandler> > QgsServerOgcApi::handlers() const
189{
190 return mHandlers;
191}
192
193
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Bad request error API exception.
The QgsServerApiContext class encapsulates the resources for a particular client request: the request...
QString handlerPath() const
Returns the handler component of the URL path, i.e.
Internal server error API exception.
Server generic API endpoint abstract base class.
Definition: qgsserverapi.h:81
QgsServerInterface Class defining interfaces exposed by QGIS Server and made available to plugins.
The QgsServerOgcApiHandler abstract class represents a OGC API handler to be registered in QgsServerO...
static QUrl sanitizeUrl(const QUrl &url)
Returns a sanitized url with extra slashes removed and the path URL component that always starts with...
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).
virtual void executeRequest(const QgsServerApiContext &context) const override SIP_THROW(QgsServerApiBadRequestException)
Executes a request by passing the given context to the API handlers.
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.
static QgsServerOgcApi::ContentType contenTypeFromExtension(const std::string &extension)
Returns the Content-Type value corresponding to extension.
ContentType
Media types used for content negotiation, insert more specific first.
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.
~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.