class OpenApiParser {

    public Result parse(String urlString) throws ParsingException {
        URI openApiUrl = null;
        try {
            openApiUrl = new URI(urlString);
        } catch (URISyntaxException e) {
            throw new ParsingException("Invalid URL", e);
        }

        final ParseOptions options = new ParseOptions();
        options.setResolve(false);

        String openApiDescription;
        try {
            openApiDescription = readOpenAPIDescription(openApiUrl);
        } catch (Exception e) {
            log.error("Reading OpenAPI description from {} failed", openApiUrl, e);
            throw e;
        }
        final SwaggerParseResult result = new OpenAPIV3Parser().readContents(openApiDescription,
                null, options);
        validate(result, openApiUrl);

        String baseUrl = Optional.ofNullable(result.getOpenAPI().getServers())
                .flatMap(s -> s.stream().findFirst())
                .map(Server::getUrl)
                .orElse("");

        // if the base URL contains parameters, do not try to parse it
        if (!baseUrl.contains("{")) {
            baseUrl = openApiUrl.resolve(baseUrl).toString();
        }

        final List<Operation> operations;
        if (result.getOpenAPI().getPaths() == null) {
            operations = Collections.emptyList();
        } else {
            operations = new ArrayList<>();
            result.getOpenAPI().getPaths().forEach((path, item) ->
                    item.readOperationsMap().forEach((method, operation) ->
                            operations.add(new Operation(method.name(), path.replaceAll("\\{[^/]*}", "*")))));
        }

        return new Result(baseUrl, operations, result.getMessages());
    }

}