Mercurial > hg > orthanc
comparison OrthancFramework/Sources/RestApi/RestApi.cpp @ 4405:5466f336b09f
gathering statistics about progress of api documentation
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 24 Dec 2020 09:37:30 +0100 |
parents | ad646ff506d0 |
children | 4cb9f66a1c7c |
comparison
equal
deleted
inserted
replaced
4404:f34634916d8c | 4405:5466f336b09f |
---|---|
25 | 25 |
26 #include "../HttpServer/StringHttpOutput.h" | 26 #include "../HttpServer/StringHttpOutput.h" |
27 #include "../Logging.h" | 27 #include "../Logging.h" |
28 #include "../OrthancException.h" | 28 #include "../OrthancException.h" |
29 | 29 |
30 #include <boost/math/special_functions/round.hpp> | |
30 #include <stdlib.h> // To define "_exit()" under Windows | 31 #include <stdlib.h> // To define "_exit()" under Windows |
31 #include <stdio.h> | 32 #include <stdio.h> |
32 | 33 |
33 namespace Orthanc | 34 namespace Orthanc |
34 { | 35 { |
129 class OpenApiVisitor : public RestApiHierarchy::IVisitor | 130 class OpenApiVisitor : public RestApiHierarchy::IVisitor |
130 { | 131 { |
131 private: | 132 private: |
132 RestApi& restApi_; | 133 RestApi& restApi_; |
133 Json::Value paths_; | 134 Json::Value paths_; |
135 size_t successPathsCount_; | |
136 size_t totalPathsCount_; | |
134 | 137 |
135 public: | 138 public: |
136 explicit OpenApiVisitor(RestApi& restApi) : | 139 explicit OpenApiVisitor(RestApi& restApi) : |
137 restApi_(restApi) | 140 restApi_(restApi), |
141 paths_(Json::objectValue), | |
142 successPathsCount_(0), | |
143 totalPathsCount_(0) | |
138 { | 144 { |
139 } | 145 } |
140 | 146 |
141 virtual bool Visit(const RestApiHierarchy::Resource& resource, | 147 virtual bool Visit(const RestApiHierarchy::Resource& resource, |
142 const UriComponents& uri, | 148 const UriComponents& uri, |
143 bool hasTrailing, | 149 bool hasTrailing, |
144 const HttpToolbox::Arguments& components, | 150 const HttpToolbox::Arguments& components, |
145 const UriComponents& trailing) | 151 const UriComponents& trailing) |
146 { | 152 { |
147 const std::string path = Toolbox::FlattenUri(uri); | 153 std::string path = Toolbox::FlattenUri(uri); |
154 if (hasTrailing) | |
155 { | |
156 path += "/{...}"; | |
157 } | |
148 | 158 |
149 if (paths_.isMember(path)) | 159 if (paths_.isMember(path)) |
150 { | 160 { |
151 throw OrthancException(ErrorCode_InternalError); | 161 throw OrthancException(ErrorCode_InternalError); |
152 } | 162 } |
158 { | 168 { |
159 assert(it->second.empty()); | 169 assert(it->second.empty()); |
160 uriArguments.insert(it->first.c_str()); | 170 uriArguments.insert(it->first.c_str()); |
161 } | 171 } |
162 | 172 |
173 if (hasTrailing) | |
174 { | |
175 uriArguments.insert("..."); | |
176 } | |
177 | |
163 if (resource.HasHandler(HttpMethod_Get)) | 178 if (resource.HasHandler(HttpMethod_Get)) |
164 { | 179 { |
180 totalPathsCount_ ++; | |
181 | |
165 StringHttpOutput o1; | 182 StringHttpOutput o1; |
166 HttpOutput o2(o1, false); | 183 HttpOutput o2(o1, false); |
167 RestApiOutput o3(o2, HttpMethod_Get); | 184 RestApiOutput o3(o2, HttpMethod_Get); |
168 RestApiGetCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, | 185 RestApiGetCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, |
169 "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, | 186 "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, |
187 } | 204 } |
188 | 205 |
189 if (ok) | 206 if (ok) |
190 { | 207 { |
191 paths_[path]["get"] = v; | 208 paths_[path]["get"] = v; |
209 successPathsCount_ ++; | |
192 } | 210 } |
193 else | 211 else |
194 { | 212 { |
195 LOG(WARNING) << "Ignoring URI without API documentation: GET " << path; | 213 LOG(WARNING) << "Ignoring URI without API documentation: GET " << path; |
196 } | 214 } |
197 } | 215 } |
198 | 216 |
199 if (resource.HasHandler(HttpMethod_Post)) | 217 if (resource.HasHandler(HttpMethod_Post)) |
200 { | 218 { |
219 totalPathsCount_ ++; | |
220 | |
201 StringHttpOutput o1; | 221 StringHttpOutput o1; |
202 HttpOutput o2(o1, false); | 222 HttpOutput o2(o1, false); |
203 RestApiOutput o3(o2, HttpMethod_Post); | 223 RestApiOutput o3(o2, HttpMethod_Post); |
204 RestApiPostCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, | 224 RestApiPostCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, |
205 "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, | 225 "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, |
222 } | 242 } |
223 | 243 |
224 if (ok) | 244 if (ok) |
225 { | 245 { |
226 paths_[path]["post"] = v; | 246 paths_[path]["post"] = v; |
247 successPathsCount_ ++; | |
227 } | 248 } |
228 else | 249 else |
229 { | 250 { |
230 LOG(WARNING) << "Ignoring URI without API documentation: POST " << path; | 251 LOG(WARNING) << "Ignoring URI without API documentation: POST " << path; |
231 } | 252 } |
232 } | 253 } |
233 | 254 |
234 if (resource.HasHandler(HttpMethod_Delete)) | 255 if (resource.HasHandler(HttpMethod_Delete)) |
235 { | 256 { |
257 totalPathsCount_ ++; | |
258 | |
236 StringHttpOutput o1; | 259 StringHttpOutput o1; |
237 HttpOutput o2(o1, false); | 260 HttpOutput o2(o1, false); |
238 RestApiOutput o3(o2, HttpMethod_Delete); | 261 RestApiOutput o3(o2, HttpMethod_Delete); |
239 RestApiDeleteCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, | 262 RestApiDeleteCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, |
240 "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, | 263 "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, |
257 } | 280 } |
258 | 281 |
259 if (ok) | 282 if (ok) |
260 { | 283 { |
261 paths_[path]["delete"] = v; | 284 paths_[path]["delete"] = v; |
285 successPathsCount_ ++; | |
262 } | 286 } |
263 else | 287 else |
264 { | 288 { |
265 LOG(WARNING) << "Ignoring URI without API documentation: DELETE " << path; | 289 LOG(WARNING) << "Ignoring URI without API documentation: DELETE " << path; |
266 } | 290 } |
267 } | 291 } |
268 | 292 |
269 if (resource.HasHandler(HttpMethod_Put)) | 293 if (resource.HasHandler(HttpMethod_Put)) |
270 { | 294 { |
295 totalPathsCount_ ++; | |
296 | |
271 StringHttpOutput o1; | 297 StringHttpOutput o1; |
272 HttpOutput o2(o1, false); | 298 HttpOutput o2(o1, false); |
273 RestApiOutput o3(o2, HttpMethod_Put); | 299 RestApiOutput o3(o2, HttpMethod_Put); |
274 RestApiPutCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, | 300 RestApiPutCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, |
275 "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, | 301 "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, |
292 } | 318 } |
293 | 319 |
294 if (ok) | 320 if (ok) |
295 { | 321 { |
296 paths_[path]["put"] = v; | 322 paths_[path]["put"] = v; |
323 successPathsCount_ ++; | |
297 } | 324 } |
298 else | 325 else |
299 { | 326 { |
300 LOG(WARNING) << "Ignoring URI without API documentation: PUT " << path; | 327 LOG(WARNING) << "Ignoring URI without API documentation: PUT " << path; |
301 } | 328 } |
306 | 333 |
307 | 334 |
308 const Json::Value& GetPaths() const | 335 const Json::Value& GetPaths() const |
309 { | 336 { |
310 return paths_; | 337 return paths_; |
338 } | |
339 | |
340 size_t GetSuccessPathsCount() const | |
341 { | |
342 return successPathsCount_; | |
343 } | |
344 | |
345 size_t GetTotalPathsCount() const | |
346 { | |
347 return totalPathsCount_; | |
311 } | 348 } |
312 }; | 349 }; |
313 } | 350 } |
314 | 351 |
315 | 352 |
493 | 530 |
494 target["info"] = Json::objectValue; | 531 target["info"] = Json::objectValue; |
495 target["openapi"] = "3.0.0"; | 532 target["openapi"] = "3.0.0"; |
496 target["servers"] = Json::arrayValue; | 533 target["servers"] = Json::arrayValue; |
497 target["paths"] = visitor.GetPaths(); | 534 target["paths"] = visitor.GetPaths(); |
535 | |
536 assert(visitor.GetSuccessPathsCount() <= visitor.GetTotalPathsCount()); | |
537 size_t total = visitor.GetTotalPathsCount(); | |
538 if (total == 0) | |
539 { | |
540 total = 1; // Avoid division by zero | |
541 } | |
542 float coverage = (100.0f * static_cast<float>(visitor.GetSuccessPathsCount()) / | |
543 static_cast<float>(total)); | |
544 | |
545 LOG(WARNING) << "The documentation of the REST API contains " << visitor.GetSuccessPathsCount() | |
546 << " paths over a total of " << visitor.GetTotalPathsCount() << " paths " | |
547 << "(" << static_cast<unsigned int>(boost::math::iround(coverage)) << "%)"; | |
498 } | 548 } |
499 } | 549 } |