[core-client] Updated ServiceClient implementation to work with core-https#9854
[core-client] Updated ServiceClient implementation to work with core-https#9854xirzec merged 20 commits intoAzure:masterfrom
Conversation
chradek
left a comment
There was a problem hiding this comment.
Overall I like the direction this is going in! One question I had was why isn't serialization in it's own policy? I liked that deserialization was moved into one.
| // Licensed under the MIT license. | ||
|
|
||
| // eslint-disable-next-line @azure/azure-sdk/ts-no-namespaces | ||
| declare global { |
There was a problem hiding this comment.
@richardpark-msft could have used this recently 😉
There was a problem hiding this comment.
nit: I wonder whether these could be useful for other libraries too. I've seen similar functions storage (for testing though). On the other hand they are small so probably fine to have copies.
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT license. | ||
|
|
||
| /// <reference lib="dom" /> |
There was a problem hiding this comment.
Remind me because I'm fuzzy...this let's us reference DOM types as core-client developers right? But it doesn't actually pull in DOM for external consumers of this library? Does this make it so consumers don't have to specify DOM themselves as well when using this library?
There was a problem hiding this comment.
I copied this from core-http because I was getting annoying compile errors, but I think it won't require external users to import that lib since they're not compiling our source and we don't re-export types that are part of dom.
It just is supposed to give us typing for things that are from dom when we feature detect them (e.g. in serializer.ts when it checks if Blob exists.)
/cc @willmtemple who knows a thing or two because he's seen a thing or two
| PipelineRequest | ||
| } from "@azure/core-https"; | ||
|
|
||
| export interface OperationRequest extends PipelineRequest { |
There was a problem hiding this comment.
Nit: Missing docs on OperationRequest.
There was a problem hiding this comment.
This was a great comment because it made me realize that extending the request this way didn't work great with clone() on the request. I fixed that bug by moving these props into a grab-bag option that clone() can persist!
| */ | ||
| export type QueryCollectionFormat = "CSV" | "SSV" | "TSV" | "Pipes" | "Multi"; | ||
|
|
||
| export type ParameterPath = string | string[] | { [propertyName: string]: ParameterPath }; |
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT license. | ||
|
|
||
| // import { assert } from "chai"; |
There was a problem hiding this comment.
oops, this gets tested indirectly through the service client tests, though it might be useful to add more tests specifically later.
joheredi
left a comment
There was a problem hiding this comment.
It looks great! I really like how much more readable this is 😄
|
|
||
| // @public | ||
| export const MapperTypeNames: { | ||
| readonly Base64Url: "Base64Url"; |
There was a problem hiding this comment.
I'll take credit but really I just replaced a crazy utility function that made a fake enum with a simple const object. 😅
| if (operationSpec.isXML && responseSpec.bodyMapper.type.name === MapperTypeNames.Sequence) { | ||
| valueToDeserialize = | ||
| typeof valueToDeserialize === "object" | ||
| ? valueToDeserialize[responseSpec.bodyMapper.xmlElementName!] |
There was a problem hiding this comment.
do we want to validate that xmlElementName exists instead of ! it? We may be able to provide a better error message if we check for it
There was a problem hiding this comment.
I tweaked this logic slightly and had it fallback to the empty array when the element name doesn't exist.
| * @param credential The credentials used for authentication with the service. | ||
| * @param options The service client options that govern the behavior of the client. | ||
| */ | ||
| constructor(options: ServiceClientOptions = {}) { |
There was a problem hiding this comment.
I tried very hard to get rid of the old cruft. Do you know if we can ditch ServiceClientCredentials yet?
There was a problem hiding this comment.
AppConfiguration library still uses it. Not sure why their AppConfigurationCredential is not used via a request policy though.
There was a problem hiding this comment.
Yeah, I think we can move this to using custom policies with AzureKeyCredential
| const expectedStatusCodes = Object.keys(operationSpec.responses); | ||
| const hasNoExpectedStatusCodes = | ||
| expectedStatusCodes.length === 0 || | ||
| (expectedStatusCodes.length === 1 && expectedStatusCodes[0] === "default"); |
There was a problem hiding this comment.
Just a note, and probably doesn't make sense to add support until we switch to the new way of serializing/deserializing.
Autorest supports x-ms-error-response which allows users to mark responses as errors in Swagger and still be able to provide alternate deserialization rules to "default", currently we'd just see those as just another success response.
There was a problem hiding this comment.
yeah this logic is terrible and unchanged from the old stuff. I'm fine adding support here, but maybe you can file an issue to do it in a follow-up PR that is more scoped to the behavior change?
deserialization was its own policy before in core-http. The problem with serialization is that serviceClients call |
Is this something we can change in a future PR then, if not in this one? (Is there already an issue to track doing this?) It seems weird that we'd allow deserialization to be replaceable, but not serialization. We also have examples of APIs today that serialize very differently based on the content-type of the body (e.g. binary versus text) and it'd be convenient if in the code generator we could decide which serialization to apply without having to make changes to this library to support this use case. |
My understanding is that future codgen will create custom mappers/deserializers using functional composition, so this layer will really just be "process the string form into an object model and call the appropriate function". I think we could take the approach the other way too, so instead of building the request from an OperationSpec, we would have a way to pack the raw inputs (operation args) into headers/url query params/body contents. If we are able to separate out the logic correctly, the actual code we need to keep in the policies/service client will be pretty minimal. /cc @joheredi for his thoughts. |
This PR accomplishes most of the work of lifting the old
ServiceClientimplementation (and dependent code) out ofcore-httpand updates it to work withcore-https.The only thing not yet supported is XML, because I need to create another (very small) package to provide the helpers and pull in the heavy XML dependency.
Otherwise, this should be in a good enough state for us to start updating AutoRest.TypeScript to work with it.
I cleaned up the serialization/deserialization code a bit, but I'm sure there are much more opportunities to do make it even cleaner. Please feel free to suggest whatever you think would be an improvement towards readability / simplicity.
I think I've looked at it too long at this point to be able to think of non-breaking cleanups. 😅
Also remember that the eventual goal is to deprecate most of this code so that we can have codegen directly compose custom serializers.
Fixes #8615