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

com.yahoo.restapi.RestApi Maven / Gradle / Ivy

// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.restapi;

import ai.vespa.http.HttpURL;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yahoo.container.jdisc.AclMapping;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.container.jdisc.RequestHandlerSpec;
import com.yahoo.container.jdisc.RequestView;
import com.yahoo.jdisc.http.HttpRequest.Method;
import com.yahoo.security.tls.Capability;
import com.yahoo.security.tls.CapabilitySet;
import com.yahoo.security.tls.ConnectionAuthContext;

import javax.net.ssl.SSLSession;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.security.Principal;
import java.util.List;
import java.util.Optional;

/**
 * Rest API routing and response serialization
 *
 * @author bjorncs
 */
public interface RestApi {

    static Builder builder() { return new RestApiImpl.BuilderImpl(); }
    static RouteBuilder route(String pathPattern) { return new RestApiImpl.RouteBuilderImpl(pathPattern); }
    static HandlerConfigBuilder handlerConfig() { return new RestApiImpl.HandlerConfigBuilderImpl(); }

    HttpResponse handleRequest(HttpRequest request);
    ObjectMapper jacksonJsonMapper();

    /** @see com.yahoo.container.jdisc.HttpRequestHandler#requestHandlerSpec() */
    RequestHandlerSpec requestHandlerSpec();

    /** @see com.yahoo.container.jdisc.utils.CapabilityRequiringRequestHandler */
    CapabilitySet requiredCapabilities(RequestView req);

    interface Builder {
        Builder setObjectMapper(ObjectMapper mapper);
        Builder setDefaultRoute(RouteBuilder route);
        Builder addRoute(RouteBuilder route);
        Builder addFilter(Filter filter);
        /** see {@link RestApiMappers#DEFAULT_EXCEPTION_MAPPERS} for default mappers */
         Builder addExceptionMapper(Class type, ExceptionMapper mapper);
        /** see {@link RestApiMappers#DEFAULT_RESPONSE_MAPPERS} for default mappers */
         Builder addResponseMapper(Class type, ResponseMapper mapper);
        /** see {@link RestApiMappers#DEFAULT_REQUEST_MAPPERS} for default mappers */
         Builder addRequestMapper(Class type, RequestMapper mapper);
         Builder registerJacksonResponseEntity(Class type);
         Builder registerJacksonRequestEntity(Class type);
        /** Disables mappers listed in {@link RestApiMappers#DEFAULT_EXCEPTION_MAPPERS} */
        Builder disableDefaultExceptionMappers();
        /** Disables mappers listed in {@link RestApiMappers#DEFAULT_RESPONSE_MAPPERS} */
        Builder disableDefaultResponseMappers();
        Builder disableDefaultAclMapping();
        Builder requiredCapabilities(Capability... capabilities);
        Builder requiredCapabilities(CapabilitySet capabilities);
        RestApi build();
    }

    interface RouteBuilder {
        RouteBuilder name(String name);
        RouteBuilder requiredCapabilities(Capability... capabilities);
        RouteBuilder requiredCapabilities(CapabilitySet capabilities);
        RouteBuilder addFilter(Filter filter);

        // GET
        RouteBuilder get(Handler handler);
        RouteBuilder get(Handler handler, HandlerConfigBuilder config);

        // POST
        RouteBuilder post(Handler handler);
         RouteBuilder post(
                Class type, HandlerWithRequestEntity handler);
        RouteBuilder post(Handler handler, HandlerConfigBuilder config);
         RouteBuilder post(
                Class type, HandlerWithRequestEntity handler, HandlerConfigBuilder config);

        // PUT
        RouteBuilder put(Handler handler);
         RouteBuilder put(
                Class type, HandlerWithRequestEntity handler);
        RouteBuilder put(Handler handler, HandlerConfigBuilder config);
         RouteBuilder put(
                Class type, HandlerWithRequestEntity handler, HandlerConfigBuilder config);

        // DELETE
        RouteBuilder delete(Handler handler);
        RouteBuilder delete(Handler handler, HandlerConfigBuilder config);

        // PATCH
        RouteBuilder patch(Handler handler);
         RouteBuilder patch(
                Class type, HandlerWithRequestEntity handler);
        RouteBuilder patch(Handler handler, HandlerConfigBuilder config);
         RouteBuilder patch(
                Class type, HandlerWithRequestEntity handler, HandlerConfigBuilder config);

        // Default
        RouteBuilder defaultHandler(Handler handler);
        RouteBuilder defaultHandler(Handler handler, HandlerConfigBuilder config);
         RouteBuilder defaultHandler(
                Class type, HandlerWithRequestEntity handler);
         RouteBuilder defaultHandler(
                Class type, HandlerWithRequestEntity handler, HandlerConfigBuilder config);
    }

    @FunctionalInterface interface Handler {
        RESPONSE_ENTITY handleRequest(RequestContext context) throws RestApiException;
    }

    @FunctionalInterface interface HandlerWithRequestEntity {
        RESPONSE_ENTITY handleRequest(RequestContext context, REQUEST_ENTITY requestEntity) throws RestApiException;
    }

    @FunctionalInterface interface ExceptionMapper { HttpResponse toResponse(RequestContext context, EXCEPTION exception); }

    @FunctionalInterface interface ResponseMapper { HttpResponse toHttpResponse(RequestContext context, RESPONSE_ENTITY responseEntity) throws RestApiException; }

    @FunctionalInterface interface RequestMapper { Optional toRequestEntity(RequestContext context) throws RestApiException; }

    @FunctionalInterface interface Filter { HttpResponse filterRequest(FilterContext context); }

    interface HandlerConfigBuilder {
        HandlerConfigBuilder withRequiredCapabilities(Capability... capabilities);
        HandlerConfigBuilder withRequiredCapabilities(CapabilitySet capabilities);
        HandlerConfigBuilder withReadAclAction();
        HandlerConfigBuilder withWriteAclAction();
        HandlerConfigBuilder withCustomAclAction(AclMapping.Action action);
    }

    interface RequestContext {
        HttpRequest request();
        Method method();
        PathParameters pathParameters();
        QueryParameters queryParameters();
        Headers headers();
        Attributes attributes();
        Optional requestContent();
        RequestContent requestContentOrThrow();
        ObjectMapper jacksonJsonMapper();
        /** Scheme, domain and port, for the original request. Use this only for generating resources links, not for custom routing! */
        // TODO: this needs to include path and query as well, to be useful for generating resource links that need not be rewritten.
        HttpURL baseRequestURL();
        /** Full URL of the request */
        HttpURL url();
        AclMapping.Action aclAction();
        Optional userPrincipal();
        Principal userPrincipalOrThrow();
        Optional sslSession();
        Optional connectionAuthContext();
        InetSocketAddress remoteAddress();

        interface Parameters {
            Optional getString(String name);
            String getStringOrThrow(String name);
            default Optional getBoolean(String name) { return getString(name).map(Boolean::valueOf);}
            default boolean getBooleanOrThrow(String name) { return Boolean.parseBoolean(getStringOrThrow(name)); }
            default Optional getLong(String name) { return getString(name).map(Long::parseLong); }
            default long getLongOrThrow(String name) { return Long.parseLong(getStringOrThrow(name)); }
            default Optional getDouble(String name) { return getString(name).map(Double::parseDouble); }
            default int getIntegerOrThrow(String name) { return Integer.parseInt(getStringOrThrow(name)); }
            default Optional getInteger(String name) { return getString(name).map(Integer::parseInt); }
            default double getDoubleOrThrow(String name) { return Double.parseDouble(getStringOrThrow(name)); }
            default BigDecimal getBigDecimalOrThrow(String name) { return new BigDecimal(getStringOrThrow(name)); }
            default Optional getBigDecimal(String name) { return getString(name).map(BigDecimal::new); }
        }

        interface PathParameters extends Parameters {
            HttpURL.Path getFullPath();
            Optional getRest();
        }
        interface QueryParameters extends Parameters {
            HttpURL.Query getFullQuery();
            List getStringList(String name);
        }
        interface Headers extends Parameters {}

        interface Attributes {
            Optional get(String name);
            void set(String name, Object value);
        }

        interface RequestContent {
            String contentType();
            InputStream content();
        }
    }

    interface FilterContext {
        RequestContext requestContext();
        String route();
        void setPrincipal(Principal principal);
        HttpResponse executeNext();
    }
}