All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yahoo.elide.swagger.resources.ApiDocsEndpoint Maven / Gradle / Ivy

There is a newer version: 7.1.2
Show newest version
/*
 * Copyright 2017, Yahoo Inc.
 * Licensed under the Apache License, Version 2.0
 * See LICENSE file in project root for terms.
 */
package com.yahoo.elide.swagger.resources;

import static com.yahoo.elide.core.dictionary.EntityDictionary.NO_VERSION;

import com.yahoo.elide.Elide;
import com.yahoo.elide.core.dictionary.EntityDictionary;
import com.yahoo.elide.core.request.route.BasicApiVersionValidator;
import com.yahoo.elide.core.request.route.FlexibleRouteResolver;
import com.yahoo.elide.core.request.route.NullRouteResolver;
import com.yahoo.elide.core.request.route.Route;
import com.yahoo.elide.core.request.route.RouteResolver;
import com.yahoo.elide.swagger.OpenApiDocument;
import com.yahoo.elide.swagger.OpenApiDocument.MediaType;

import org.apache.commons.lang3.tuple.Pair;

import io.swagger.v3.oas.models.OpenAPI;

import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * A convenience endpoint to expose a openapi document.
 */

@Path("/")
public class ApiDocsEndpoint {
    //Maps api version & path to a openapi document.
    protected Map, OpenApiDocument> documents;
    protected final RouteResolver routeResolver;

    @Data
    @AllArgsConstructor
    public static class ApiDocsRegistration {
        private String path;
        private Supplier document;

        /**
         * The API version.
         */
        private String apiVersion;
    }

    /**
     * Constructs the resource.
     *
     * @param docs Map of path parameter name to openapi document.
     */
    @Inject
    public ApiDocsEndpoint(@Named("apiDocs") List docs,
            @Named("elide") Elide elide, Optional optionalRouteResolver
            ) {
        documents = new HashMap<>();

        docs.forEach(doc -> {
            String apiVersion = doc.getApiVersion();
            apiVersion = apiVersion == null ? NO_VERSION : apiVersion;
            String apiPath = doc.path;
            documents.put(Pair.of(apiVersion, apiPath), new OpenApiDocument(doc.document));
        });

        this.routeResolver = optionalRouteResolver.orElseGet(() -> {
            Set apiVersions = elide.getElideSettings().getEntityDictionary().getApiVersions();
            if (apiVersions.size() == 1 && apiVersions.contains(EntityDictionary.NO_VERSION)) {
                return new NullRouteResolver();
            } else {
                return new FlexibleRouteResolver(new BasicApiVersionValidator(), elide.getElideSettings()::getBaseUrl);
            }
        });
    }

    @GET
    @Path("{path:.*}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response listJson(
            @PathParam("path") String path,
            @Context UriInfo uriInfo,
            @Context HttpHeaders headers
            ) {
        Route route = routeResolver.resolve(MediaType.APPLICATION_JSON, "", path, headers.getRequestHeaders(),
                uriInfo.getQueryParameters());
        String name = route.getPath();
        if (name.startsWith("/")) {
            name = name.substring(1);
        }
        if (name.isBlank()) {
            return list(route.getApiVersion(), MediaType.APPLICATION_JSON);
        } else {
            return get(route.getApiVersion(), name, MediaType.APPLICATION_JSON);
        }
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response listJson(
            @Context UriInfo uriInfo,
            @Context HttpHeaders headers
            ) {
        return listJson("", uriInfo, headers);
    }

    @GET
    @Path("{path:.*}")
    @Produces(MediaType.APPLICATION_YAML)
    public Response listYaml(
            @PathParam("path") String path,
            @Context UriInfo uriInfo,
            @Context HttpHeaders headers
    ) {
        Route route = routeResolver.resolve(MediaType.APPLICATION_YAML, "", path, headers.getRequestHeaders(),
                uriInfo.getQueryParameters());
        String name = route.getPath();
        if (name.startsWith("/")) {
            name = name.substring(1);
        }
        if (name.isBlank()) {
            return list(route.getApiVersion(), MediaType.APPLICATION_YAML);
        } else {
            return get(route.getApiVersion(), name, MediaType.APPLICATION_YAML);
        }
    }

    @GET
    @Produces(MediaType.APPLICATION_YAML)
    public Response listYaml(
            @Context UriInfo uriInfo,
            @Context HttpHeaders headers
            ) {
        return listYaml("", uriInfo, headers);
    }

    public Response list(String apiVersion, String mediaType) {
        String safeApiVersion = apiVersion == null ? NO_VERSION : apiVersion;

        final List documentPaths = documents.keySet().stream()
                .filter(key -> key.getLeft().equals(safeApiVersion)).map(Pair::getRight).toList();

        if (documentPaths.size() == 1) {
            Optional> pair = documents.keySet().stream()
                    .filter(key -> key.getLeft().equals(safeApiVersion)).findFirst();
            if (pair.isPresent()) {
                return Response.ok(documents.get(pair.get()).ofMediaType(mediaType)).build();
            }
        }

        String body = documentPaths.stream().map(key -> '"' + key + '"')
                .collect(Collectors.joining(",", "[", "]"));

        return Response.ok(body).build();
    }

    public Response get(String apiVersion, String name, String mediaType) {
        String safeApiVersion = apiVersion == null ? NO_VERSION : apiVersion;
        Pair lookupKey = Pair.of(safeApiVersion, name);
        if (documents.containsKey(lookupKey)) {
            return Response.ok(documents.get(lookupKey).ofMediaType(mediaType)).build();
        }
        return Response.status(404).entity("Unknown document: " + name).build();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy