001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.rest.client;
018
019/**
020 * Lifecycle interceptor for REST calls made by {@link RestClient}.
021 *
022 * <p>
023 * Registered on the client builder via {@link RestClient.Builder#interceptors(RestCallInterceptor...)}.
024 * All callbacks have default no-op implementations so implementations only need to override the hooks they care about.
025 *
026 * <h5 class='section'>Example:</h5>
027 * <p class='bjava'>
028 *    RestClient <jv>client</jv> = RestClient.<jsm>builder</jsm>()
029 *       .transport(<jv>transport</jv>)
030 *       .interceptors(new RestCallInterceptor() {
031 *          &#64;Override
032 *          <jk>public void</jk> onConnect(RestRequest req, RestResponse res) {
033 *             System.<jf>out</jf>.println(<js>"Response: "</js> + res.getStatusCode());
034 *          }
035 *       })
036 *       .build();
037 * </p>
038 *
039 * <h5 class='section'>See Also:</h5><ul>
040 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/NextGenRestClient">Next-Generation REST Client</a>
041 * </ul>
042 *
043 * @since 9.2.1
044 */
045@SuppressWarnings({
046   "java:S112" // Interceptor SPI callbacks intentionally declare 'throws Exception' so implementations may abort a call with any exception type.
047})
048public interface RestCallInterceptor {
049
050   /**
051    * Called before the transport request is built and sent.
052    *
053    * <p>
054    * Use this hook to add headers, modify query parameters, or short-circuit the call.
055    *
056    * @param req The request being built. Never <jk>null</jk>.
057    * @throws Exception If the call should be aborted.
058    */
059   default void onInit(RestRequest req) throws Exception {}
060
061   /**
062    * Called after a response has been received from the transport.
063    *
064    * <p>
065    * Use this hook to inspect status codes, validate headers, or modify how the response is interpreted.
066    *
067    * @param req The request that was sent. Never <jk>null</jk>.
068    * @param res The response received. Never <jk>null</jk>.
069    * @throws Exception If a post-connect error should be raised.
070    */
071   default void onConnect(RestRequest req, RestResponse res) throws Exception {}
072
073   /**
074    * Called when the request is being closed (in the {@code finally} block of {@link RestRequest#run()}).
075    *
076    * <p>
077    * This is called regardless of whether the call succeeded or failed, and is always invoked before
078    * the logger receives its entry. Use it for cleanup, metrics recording, or span/trace finalization.
079    *
080    * @param req The request. Never <jk>null</jk>.
081    * @param res The response, or <jk>null</jk> if the transport failed before a response was received.
082    * @throws Exception If an error occurs during close handling.
083    */
084   default void onClose(RestRequest req, RestResponse res) throws Exception {}
085}