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

no.nav.apiapp.rest.SwaggerResource Maven / Gradle / Ivy

package no.nav.apiapp.rest;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.jaxrs.config.DefaultJaxrsScanner;
import io.swagger.jaxrs.config.ReaderConfigUtils;
import io.swagger.jaxrs.listing.BaseApiListingResource;
import io.swagger.models.Operation;
import io.swagger.models.Swagger;
import io.swagger.models.parameters.HeaderParameter;
import io.swagger.models.properties.StringProperty;
import io.swagger.util.Json;
import lombok.SneakyThrows;
import no.nav.apiapp.ApiApplication;
import no.nav.log.LogFilter;
import org.springframework.stereotype.Component;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.*;
import java.lang.reflect.Method;
import java.util.*;

import static java.util.Arrays.stream;
import static java.util.Optional.ofNullable;
import static no.nav.apiapp.util.UrlUtils.sluttMedSlash;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;

@Component
@Path("/" + SwaggerResource.SWAGGER_JSON)
public class SwaggerResource extends BaseApiListingResource {

    public static final String SWAGGER_JSON = "swagger.json";
    public static final String IKKE_BERIK = "ikke_berik";

    private final ApiApplication apiApplication;
    private final boolean hasLogin;

    public static void setupServlet(ServletRegistration.Dynamic servletRegistration) {
        servletRegistration.setInitParameter("scan.all.resources", "true");
    }

    public SwaggerResource(ApiApplication apiApplication, boolean hasLogin) {
        this.apiApplication = apiApplication;
        this.hasLogin = hasLogin;
    }

    @Inject
    private Provider httpServletRequestProvider;

    @GET
    public Response getSwaggerJSON(
            @Context Application application,
            @Context ServletConfig servletConfig,
            @Context ServletContext servletContext,
            @Context HttpHeaders httpHeaders,
            @Context UriInfo uriInfo,
            @QueryParam(IKKE_BERIK) String ikkeBerik
    ) throws JsonProcessingException {
        ReaderConfigUtils.initReaderConfig(servletConfig);
        return getListingJsonResponse(application, servletContext, servletConfig, httpHeaders, uriInfo);
    }

    @Override
    protected Swagger process(Application app, ServletContext servletContext, ServletConfig sc, HttpHeaders headers, UriInfo uriInfo) {
        Swagger swagger = super.process(app, servletContext, sc, headers, uriInfo);
        if (!httpServletRequestProvider.get().getParameterMap().containsKey(IKKE_BERIK)) {
            return berik(
                    kopier(swagger), //  BaseApiListingResource cacher swagger-objektet, kopierer derfor for å ikke mutere på dette
                    app,
                    servletContext,
                    sc
            );
        } else {
            return swagger;
        }
    }

    @SneakyThrows
    private Swagger kopier(Swagger swagger) {
        ObjectMapper mapper = Json.mapper();
        return mapper.readValue(mapper.writeValueAsString(swagger), Swagger.class);
    }

    private Swagger berik(Swagger swagger, Application app, ServletContext servletContext, ServletConfig sc) {
        swagger.setBasePath(servletContext.getContextPath() + sluttMedSlash(apiApplication.getApiBasePath()));
        SwaggerRequest swaggerRequest = new SwaggerRequest(swagger);
        new DefaultJaxrsScanner().classesFromContext(app, sc).forEach(res -> leggTilStandardDokumentasjon(swaggerRequest, res));
        return swagger;
    }

    private void leggTilStandardDokumentasjon(SwaggerRequest swaggerRequest, Class contextClass) {
        ofNullable(findAnnotation(contextClass, Path.class))
                .map(Path::value)
                .map(this::prependSlash)
                .ifPresent(resourcePath -> leggTilStandardDokumentasjon(swaggerRequest, contextClass, contextClass, resourcePath));
    }

    private void leggTilStandardDokumentasjon(SwaggerRequest swaggerRequest, Class methodsClass, Class contextClass, String resourcePath) {
        stream(methodsClass.getMethods()).forEach(method -> leggTilStandardDokumentasjon(swaggerRequest, method, resourcePath, contextClass));
    }

    private void leggTilStandardDokumentasjon(SwaggerRequest swaggerRequest, Method method, String resourcePath, Class contextClass) {
        if (swaggerRequest.methods.contains(method)) {
            return;
        } else {
            swaggerRequest.methods.add(method);
        }

        String methodPath = ofNullable(findAnnotation(method, Path.class))
                .map(Path::value)
                .map(this::prependSlash)
                .orElse("");
        String path = resourcePath + ("/".equals(methodPath) ? "" : methodPath);
        leggTilStandardDokumentasjon(swaggerRequest, method.getReturnType(), contextClass, path);

        ofNullable(swaggerRequest.swagger.getPath(path))
                .flatMap(swaggerPath -> getOperation(swaggerPath, method))
                .ifPresent(operation -> {

                    HeaderParameter consumerIdParameter = new HeaderParameter();
                    consumerIdParameter.setName(LogFilter.CONSUMER_ID_HEADER_NAME);
                    consumerIdParameter.setDescription("the consuming entity of the request, typically the name of an application");
                    consumerIdParameter.setType("string");
                    operation.addParameter(consumerIdParameter);

                    HeaderParameter callIdParameter = new HeaderParameter();
                    callIdParameter.setName(LogFilter.PREFERRED_NAV_CALL_ID_HEADER_NAME);
                    callIdParameter.setDescription("a correlation id that is added to logs associated with the request");
                    callIdParameter.setType("string");
                    operation.addParameter(callIdParameter);

                    if (hasLogin) {
                        HeaderParameter authorizationParameters = new HeaderParameter();
                        authorizationParameters.setName(HttpHeaders.AUTHORIZATION);
                        authorizationParameters.setType("string");
                        operation.addParameter(authorizationParameters);

                        io.swagger.models.Response response = new io.swagger.models.Response();
                        response.setDescription("the request was not authenticated or authorized");
                        operation.response(401, response);
                    }

                    operation.getResponses().values().forEach(response->{
                        response.addHeader(LogFilter.PREFERRED_NAV_CALL_ID_HEADER_NAME, new StringProperty());
                    });

                    if (ofNullable(operation.getTags()).map(List::isEmpty).orElse(true)) {
                        operation.addTag(contextClass.getSimpleName());
                    }
                    operation.setSummary(ofNullable(operation.getSummary())
                            .orElse(method.getName())
                    );
                });
    }

    private Optional getOperation(io.swagger.models.Path swaggerPath, Method method) {
        Map operationsByMethod = swaggerPath.getOperationMap();
        return ofNullable(findAnnotation(method, HttpMethod.class))
                .map(HttpMethod::value)
                .map(io.swagger.models.HttpMethod::valueOf)
                .map(operationsByMethod::get);
    }

    private String prependSlash(String path) {
        return path.startsWith("/") ? path : "/" + path;
    }

    private static class SwaggerRequest {
        private Set methods = new HashSet<>();
        private final Swagger swagger;

        private SwaggerRequest(Swagger swagger) {
            this.swagger = swagger;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy