/** * Tries to find the best fitting API path matching the given path and request method. * * @param path the requests path to find in API definition * @param method the {@link Request.Method} for the request * @return a {@link ApiOperationMatch} containing the information if the path is defined, the operation * is allowed and having the necessary {@link ApiOperation} if applicable */ @Nonnull public ApiOperationMatch findApiOperation(final String path, final Request.Method method) { // try to find possible matching paths regardless of HTTP method final NormalisedPath requestPath = new NormalisedPathImpl(path, apiPrefix); final List<ApiPath> matchingPaths = apiPathsGroupedByNumberOfParts .getOrDefault(requestPath.numberOfParts(), emptyList()).stream() .filter(p -> p.matches(requestPath)) .collect(toList()); if (matchingPaths.isEmpty()) { return ApiOperationMatch.MISSING_PATH; } // try to find the operation which fits the HTTP method, // choosing the most 'specific' path match from the candidates final PathItem.HttpMethod httpMethod = PathItem.HttpMethod.valueOf(method.name()); final Optional<ApiPath> matchingPathAndOperation = matchingPaths.stream() .filter(apiPath -> operations.contains(apiPath.original(), httpMethod)) .max(comparingInt(ApiOperationResolver::specificityScore)); return matchingPathAndOperation .map(match -> new ApiOperationMatch(new ApiOperation(match, requestPath, httpMethod, operations.get(match.original(), httpMethod)))) .orElse(ApiOperationMatch.NOT_ALLOWED_OPERATION); }
@Nonnull private ValidationReport validateHeader(final ApiOperation apiOperation, final String headerName, final Header apiHeader, final Collection<String> propertyValues) { if (propertyValues.isEmpty() && TRUE.equals(apiHeader.getRequired())) { return ValidationReport.singleton( messages.get("validation.response.header.missing", headerName, apiOperation.getApiPath().original()) ); } return propertyValues .stream() .map(v -> schemaValidator.validate(v, apiHeader.getSchema(), "response.header")) .reduce(ValidationReport.empty(), ValidationReport::merge); } }
public Optional<OpenApiOperation> findApiOperation(String method, String path) { String relativePath = UrlUtils.extractPath(path); Request.Method requestMethod = Enum.valueOf(Request.Method.class, method); ApiOperationMatch apiOperation = apiOperationResolver.findApiOperation(relativePath, requestMethod); if (! apiOperation.isPathFound() || ! apiOperation.isOperationAllowed()) { return Optional.empty(); } return Optional.of(new OpenApiOperation(method, combineWithBasePath(apiOperation.getApiOperation().getApiPath().original()))); }
@Nonnull private ValidationReport validateParameter(final ApiOperation apiOperation, final Parameter parameter, final Collection<String> parameterValues, final String missingKey) { final ValidationReport.MessageContext context = ValidationReport.MessageContext.create().withParameter(parameter).build(); if (parameterValues.isEmpty() && TRUE.equals(parameter.getRequired())) { return ValidationReport.singleton( messages.get(missingKey, parameter.getName(), apiOperation.getApiPath().original()) ).withAdditionalContext(context); } return parameterValues .stream() .map(v -> parameterValidator.validate(v, parameter)) .reduce(empty(), ValidationReport::merge); }
return ValidationReport.singleton( messages.get("validation.response.body.missing", apiOperation.getMethod(), apiOperation.getApiPath().original()) );
return ValidationReport.singleton( messages.get("validation.response.status.unknown", response.getStatus(), apiOperation.getApiPath().original()) ).withAdditionalContext(contextBuilder.build());