@@ -72,6 +72,8 @@ trait GapicClientTrait
7272 private string $ serviceName = '' ;
7373 private array $ agentHeader = [];
7474 private array $ descriptors = [];
75+ /** @var array<callable> $prependMiddlewareCallables */
76+ private array $ prependMiddlewareCallables = [];
7577 /** @var array<callable> $middlewareCallables */
7678 private array $ middlewareCallables = [];
7779 private array $ transportCallMethods = [
@@ -118,6 +120,42 @@ public function addMiddleware(callable $middlewareCallable): void
118120 $ this ->middlewareCallables [] = $ middlewareCallable ;
119121 }
120122
123+ /**
124+ * Prepend a middleware to the call stack by providing a callable which will be
125+ * invoked at the end of each call, and will return an instance of
126+ * {@see MiddlewareInterface} when invoked.
127+ *
128+ * The callable must have the following method signature:
129+ *
130+ * callable(MiddlewareInterface): MiddlewareInterface
131+ *
132+ * An implementation may look something like this:
133+ * ```
134+ * $client->prependMiddleware(function (MiddlewareInterface $handler) {
135+ * return new class ($handler) implements MiddlewareInterface {
136+ * public function __construct(private MiddlewareInterface $handler) {
137+ * }
138+ *
139+ * public function __invoke(Call $call, array $options) {
140+ * // modify call and options (pre-request)
141+ * $response = ($this->handler)($call, $options);
142+ * // modify the response (post-request)
143+ * return $response;
144+ * }
145+ * };
146+ * });
147+ * ```
148+ *
149+ * @param callable $middlewareCallable A callable which returns an instance
150+ * of {@see MiddlewareInterface} when invoked with a
151+ * MiddlewareInterface instance as its first argument.
152+ * @return void
153+ */
154+ public function prependMiddleware (callable $ middlewareCallable ): void
155+ {
156+ $ this ->prependMiddlewareCallables [] = $ middlewareCallable ;
157+ }
158+
121159 /**
122160 * Initiates an orderly shutdown in which preexisting calls continue but new
123161 * calls are immediately cancelled.
@@ -663,6 +701,12 @@ private function createCallStack(array $callConstructionOptions)
663701 $ startCallMethod = $ this ->transportCallMethods [$ call ->getCallType ()];
664702 return $ this ->transport ->$ startCallMethod ($ call , $ options );
665703 };
704+
705+ foreach (\array_reverse ($ this ->prependMiddlewareCallables ) as $ fn ) {
706+ /** @var MiddlewareInterface $callStack */
707+ $ callStack = $ fn ($ callStack );
708+ }
709+
666710 $ callStack = new CredentialsWrapperMiddleware ($ callStack , $ this ->credentialsWrapper );
667711 $ callStack = new FixedHeaderMiddleware ($ callStack , $ fixedHeaders , true );
668712 $ callStack = new RetryMiddleware ($ callStack , $ callConstructionOptions ['retrySettings ' ]);
0 commit comments