Azure / azure-sdk-for-js

This repository is for active development of the Azure SDK for JavaScript (NodeJS & Browser). For consumers of the SDK we recommend visiting our public developer docs at https://docs.microsoft.com/javascript/azure/ or our versioned developer docs at https://azure.github.io/azure-sdk-for-js.

Repository from Github https://github.comAzure/azure-sdk-for-jsRepository from Github https://github.comAzure/azure-sdk-for-js

Attempting to invoke a request with a malformed pipeline should fail loudly

zheng opened this issue · comments

  • Package Name: @azure/core-rest-pipeline
  • Package Version: 1.18.1
  • Operating system: Node v20
    The issue is demonstrated with npm:@azure/arm-resources@5.2.0, but I'm guessing this happens more generally

Describe the bug
Using createPipelineFromOptions to construct an Azure pipeline results in an improperly formed object, which causes all network requests to silently fail by returning empty values instead of producing an error. There is no explicit indication in the documentation that createPipelineFromOptions should not be used in this way, but further inspection suggests that it is intended for internal Azure libraries due to its dependency on InternalPipelineOptions. As a result, when this pipeline is used with a ResourceManagementClient, iterator calls return { value: undefined, done: true } instead of expected API responses.

To Reproduce
Steps to reproduce the behavior:

  1. Create a pipeline using createPipelineFromOptions
  2. Create a ResourceManagementClient with the pipeline
  3. Invoke the providers endpoint
    Node shell outputs:
> const pipeline = createPipelineFromOptions({retryOptions: defaultRetryOptions});
> await new ResourceManagementClient(c, <secret>, { baseUri, pipeline}).providers.list().next();
{ value: undefined, done: true }

Contrast this with the expected behavior by using the client without a passed pipeline, which produces a valid response.

Expected behavior
If createPipelineFromOptions is not meant to be used in this way, the documentation should explicitly state that it is intended for internal Azure libraries and should not be used to construct pipelines. Additionally, the failure mode should be more explicit—instead of silently returning { value: undefined, done: true }, the API should produce a clear error indicating that the pipeline is invalid or missing required components.

If I understand your issue, you are using a fresh pipeline from core-rest-pipeline to initialize a service client. Part of the trouble here is that client pipelines that use ServiceClient need to have a serialization policy that normally gets added here:

pipeline.addPolicy(serializationPolicy(options.serializationOptions), { phase: "Serialize" });

The other trouble I think you are running into is ARM clients directly export their generated subclass of ServiceClient, which exposes internal fields like pipeline which create confusion as you noted. ServiceClientOptions ultimately extends from PipelineOptions however, so you don't have to pass in a custom pipeline in order to pass these options down properly:

await new ResourceManagementClient(c, <secret>, { baseUri, retryOptions: defaultRetryOptions }).providers.list().next();

This should do what you actually want without having to manage a pipeline directly, as your retry options will get passed to createClientPipeline and then to createPipelineFromOptions from there.

I agree that we can adjust the doc comments for pipeline to be more explicit that this is an internal/advanced property. Part of the reason for this ugliness is for dataplane SDKs we have some convenience clients that needed to override ServiceClient behavior. This should be addressed by some upcoming changes to our SDK codegen that removes ServiceClient entirely.