From 347e7fbfface2e00cbc1063000d8ecad9228f707 Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Wed, 23 Dec 2020 17:21:44 -0500 Subject: [PATCH 1/2] add docs --- docs/client/initializing.md | 51 ++++++++ docs/client/models.md | 20 +++ docs/client/operations.md | 118 ++++++++++++++++++ docs/client/readme.md | 17 +++ docs/client/tracing.md | 84 +++++++++++++ docs/client/troubleshooting.md | 34 +++++ docs/faq.md | 16 +++ docs/generate/troubleshooting.md | 38 ++++++ docs/images/logo.png | Bin 0 -> 20582 bytes docs/migrate/readme.md | 11 ++ docs/readme.md | 37 ++++++ docs/samples/readme.md | 16 +++ docs/samples/specification/basic/readme.md | 10 ++ .../specification/management/readme.md | 16 +++ 14 files changed, 468 insertions(+) create mode 100644 docs/client/initializing.md create mode 100644 docs/client/models.md create mode 100644 docs/client/operations.md create mode 100644 docs/client/readme.md create mode 100644 docs/client/tracing.md create mode 100644 docs/client/troubleshooting.md create mode 100644 docs/faq.md create mode 100644 docs/generate/troubleshooting.md create mode 100644 docs/images/logo.png create mode 100644 docs/migrate/readme.md create mode 100644 docs/readme.md create mode 100644 docs/samples/readme.md create mode 100644 docs/samples/specification/basic/readme.md create mode 100644 docs/samples/specification/management/readme.md diff --git a/docs/client/initializing.md b/docs/client/initializing.md new file mode 100644 index 0000000000..ea873938a4 --- /dev/null +++ b/docs/client/initializing.md @@ -0,0 +1,51 @@ +# Initializing Your Typescript Client + +The first step to using your generated client in code is to import and initialize your client. Our SDKs are modelled such +that the client is the main point of access to the generated code. + +## Importing Your Client + +You import your client from the package specified when generating (under flag `--package-name`). For the sake of this example, +let's say the namespace is `@azure/pets`. Your client's name is detailed in the swagger, (TODO link to swagger docs), and let's say +ours is called `PetsClient`. + +Putting this together, we import our client like so: + +```js +import { PetsClient } from "@azure/pets"; +``` + +## Initializing and Authenticating Your Client + +Next, on to initialization. Your constructor can take any number of parameters. For the most basic client with no parameters, you can initialize your client like so: + +```js +import { PetsClient } from "@azure/pets"; + +let client: PetsClient; + +client = new PetsClient(); +``` + +If you generate with flag `--add-credentials`, your client wil be generated with an [Azure Active Directory (AAD) token credential][aad_authentication]. We always recommend +using a [credential type][identity_credentials] obtained from the [`@azure/identity`][azure_identity_library] library for AAD authentication. For this example, +we use the most common [`DefaultAzureCredential`][default_azure_credential]. + +As an installation note, the [`@azure/identity`][azure_identity_library] library is not a requirement in our generated `package.json` file, so you would need to install this library separately. + +```js +import { DefaultAzureCredential } from "@azure/identity"; +import { PetsClient } from "@azure/pets"; + +let client: PetsClient; + +client = new PetsClient(new DefaultAzureCredential()); +``` + + +[azure_identity_library]: https://www.npmjs.com/package/@azure/identity +[flag_index]: https://github.com/Azure/autorest/tree/master/docs/generate/flags.md +[aad_authentication]: https://docs.microsoft.com/en-us/azure/cognitive-services/authentication?tabs=powershell#authenticate-with-azure-active-directory +[identity_credentials]: https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/identity/identity#credential-classes +[default_azure_credential]: https://docs.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential?view=azure-node-latest +[azure_key_credential]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.credentials.azurekeycredential?view=azure-python diff --git a/docs/client/models.md b/docs/client/models.md new file mode 100644 index 0000000000..5c58845939 --- /dev/null +++ b/docs/client/models.md @@ -0,0 +1,20 @@ +# Accessing Models and Enums + +## General + +Models and enums are generated in the `models` namespace. So, say you are using package `@azure/pets`. To access model `Dog`, you would use the following code +snippet + +```js +import { Dog } from "@azure/pets.models"; +``` + +Enums are also listed in the `models` namespace, so say you have enum class `DogTypes`. To access the `Dalmation` enum, your code would look like + +```js +import { DogTypes } from "@azure/pets.models"; + +let dogType: str; + +dogType = DogTypes.Dalmation; +``` diff --git a/docs/client/operations.md b/docs/client/operations.md new file mode 100644 index 0000000000..c310e64995 --- /dev/null +++ b/docs/client/operations.md @@ -0,0 +1,118 @@ +# Calling Operations with Your Typescript Client + +AutoRest provides both synchronous and asynchronous method overloads for each service operation. +Depending on your swagger definition, operations can be accessed through operation groups (TODO: link to swagger docs) on the client, +or directly on the client. + +## Operation Group vs No Operation Group + +If your swagger defines an operation group for your operation (for example, in [this][operation_group_example] swagger, the operation `list` +is part of operation group `application`), you would access the operation through `client.application.list()`. + +If there's no operation group, as in [this][mixin_example] case, you would access the operation directly from the client +itself, i.e. `client.getDog()`. + +## Regular Operations + +### Sync Operations + +We don't generate sync operations, all of our operations are async. + +### Async Operations + +When calling our async operations, we use our async client, which is in a different module. Following the [example above](#sync-operations Sync Operations), +our call to `getDog` looks like this: + +```js +import { DefaultAzureCredential } from "@azure/identity"; +import { PetsClient } from "@azure/pets"; + +let client: PetsClient; + +client = new PetsClient(new DefaultAzureCredential()); +const dog = await client.getDog(); +``` + +## Long Running Operations + +Long-running operations are operations which consist of an initial request sent to the service to start an operation, followed by polling the service at intervals to determine whether the operation has completed or failed, and if it has succeeded, to get the result. + +In concurrence with our [typescript guidelines][poller_guidelines], all of our long running operations are prefixed with `begin`, to signify the starting of the long running operation. + +For our example, we will use the long running operation generated from [this][example_swagger] swagger. Let's say we generated this swagger with package name `@azure/lro`. + +### Sync Long Running Operations + +We don't generate sync operations, all of our operations are async. + +### Async Long Running Operations + +By default, our async long running operations return an [`Poller`][poller] polling object, though there [are ways][custom_poller] of changing this. Calling `.pollUntilDone()` +on the poller will wait until the long running operation finishes then return the final result. + +```js +import { DefaultAzureCredential } from "@azure/identity"; +import { Product, PollingPagingExampleClient } from "@azure/lro"; + +let client: PollingPagingExampleClient; +let inputProduct: Product; + +client = new PollingPagingExampleClient(new DefaultAzureCredential()); + +inputProduct = { + id: 1; + name: "My Polling example" +}; + +const poller = await client.beginBasicPolling(inputProduct); +const outputProduct = await poller.pollUntilDone(); +``` + +## Paging Operations + +A paging operation pages through lists of data, returning an iterator for the items. Network calls get made when users start iterating through the output, not when the operation +is initially called. + +For our example, we will use the long running operation generated from [this][example_swagger] swagger. Let's say we generated this swagger with package name `@azure/paging`. + +### Sync Paging Operations + +We don't generate sync operations, all of our operations are async. + +### Async Paging Operations + +By default, our sync paging operations return an [`PagedAsyncIterableIterator`][paged_async_iterable_iterator] pager. Since network calls aren't +made until starting to page, our generated operation is synchronous, and there's no need to wait the initial call to the function. Since network calls are made when iterating, +we have to do async looping. + +```js +import { DefaultAzureCredential } from "@azure/identity"; +import { PollingPagingExampleClient } from "@azure/paging"; + +let client: PollingPagingExampleClient; + +client = new PollingPagingExampleClient(new DefaultAzureCredential()); + +const pager = client.basicPaging(); +for await (const product of pager) { + console.log(`${product.id}, ${product.name}`); +} +``` + +## Advanced: LRO + paging + +We also support generating a long running paging operation. In this case, we return a poller from the operation, and the final result from the poller is +a pager that pages through the final lists of data. + + + +[operation_group_example]: https://github.com/Azure/azure-rest-api-specs/blob/master/specification/batch/data-plane/Microsoft.Batch/stable/2020-09-01.12.0/BatchService.json#L64 +[mixin_example]: https://github.com/Azure/autorest/blob/new_docs/docs/openapi/examples/pets.json#L20 +[pets_swaggger]: https://github.com/Azure/autorest/blob/new_docs/docs/openapi/examples/pets.json +[initializing]: ./initializing.md +[poller]: https://docs.microsoft.com/en-us/javascript/api/@azure/core-lro/poller?view=azure-node-latest +[custom_poller]: ../generate/directives.md#generate-with-a-custom-poller +[example_swagger]: ../samples/specification/directives/pollingPaging.json +[poller_guidelines]: https://azure.github.io/azure-sdk/typescript_design.html#ts-lro +[custom_pager]: ../generate/directives.md#generate-with-a-custom-pager +[paged_async_iterable_iterator]: https://docs.microsoft.com/en-us/javascript/api/@azure/core-paging/pagedasynciterableiterator?view=azure-node-latest \ No newline at end of file diff --git a/docs/client/readme.md b/docs/client/readme.md new file mode 100644 index 0000000000..662af18b34 --- /dev/null +++ b/docs/client/readme.md @@ -0,0 +1,17 @@ +# Using the Typescript Client + +After [generating][generate] your client, this section tells you how to actually use your generated client. + +* [Initializing Your Typescript Client][initializing] +* [Calling Operations with Your Typescript Client][operations] +* [Accessing Models and Enums][models] +* [Troubleshooting][troubleshooting] +* [Tracing][tracing] + + +[generate]: https://github.com/Azure/autorest/tree/master/docs/generate/readme.md +[initializing]: ./initializing.md +[operations]: ./operations.md +[models]: ./models.md +[troubleshooting]: ./troubleshooting.md +[tracing]: ./tracing.md \ No newline at end of file diff --git a/docs/client/tracing.md b/docs/client/tracing.md new file mode 100644 index 0000000000..32d8dff4cd --- /dev/null +++ b/docs/client/tracing.md @@ -0,0 +1,84 @@ +# Tracing + +Our generated code natively [`OpenCensus`][open_census] and [`OpenTelemetry`][open_telemetry]. To do so, generate with flag `--trace` (see our [flag index][flag_index] for more information). +By default, all libraries log with a NoOpTracer that takes no action. To change this, you have to use setTracer to set a new default Tracer. + +To trace, make sure you install [our tracing library][tracing_library]: + +``` +npm install @azure/core-tracing +``` + +## OpenCensus + +Our generated SDKs handle retrieving context for you, so there's no need to pass in any context. Additionally, the +OpenCensus threading plugin is included when installing this package. + +Since there is no explicit context you need to pass, you can create your usual OpenCensus tracer and call the generated SDKs. +The following example uses the [Zipkin][zipkin] exporter. + +```js +const tracing = require("@opencensus/nodejs"); +const { ZipkinTraceExporter } = require("@opencensus/exporter-zipkin"); +const { + setTracer, + OpenCensusTracerWrapper, + OpenCensusSpanWrapper +} = require("@azure/core-tracing"); + +const tracer = tracing.start({ samplingRate: 1 }).tracer; + +tracer.registerSpanEventListener( + new ZipkinTraceExporter({ + serviceName: "azure-tracing-sample", + bufferTimeout: 2 + }) +); +setTracer(new OpenCensusTracerWrapper(tracer)); +tracer.startRootSpan({ name: "root" }, async (rootSpanEx) => { + const rootSpan = new OpenCensusSpanWrapper(rootSpanEx); + // Call some client library methods and pass rootSpan via tracingOptions. + rootSpanEx.end(); // rootSpan.end() should work as well +}); +``` + +## OpenTelemetry + +First step is to install our [`OpenTelemetry` library][our_open_telemetry_library]: + +```python +pip install azure-core-tracing-opentelemetry +``` + +Since there is no explicit context you need to pass, you can create your usual OpenTelemetry tracer and call the generated SDKs. +The following example uses the [Zipkin][zipkin] exporter. +```js +const opentelemetry = require("@opentelemetry/core"); +const { BasicTracer, SimpleSpanProcessor } = require("@opentelemetry/tracing"); +const { ZipkinExporter } = require("@opentelemetry/exporter-zipkin"); +const { setTracer } = require("@azure/core-tracing"); + +const exporter = new ZipkinExporter({ + serviceName: "azure-tracing-sample" +}); +const tracer = new BasicTracer(); +tracer.addSpanProcessor(new SimpleSpanProcessor(exporter)); + +opentelemetry.initGlobalTracer(tracer); + +const rootSpan = opentelemetry.getTracer().startSpan("root"); + +// Call some client library methods and pass rootSpan via tracingOptions. + +rootSpan.end(); +exporter.shutdown(); +``` + + +[open_census]: https://opencensus.io/ +[open_telemetry]: https://opentelemetry.io/ +[flag_index]: https://github.com/Azure/autorest/tree/master/docs/generate/flags.md +[tracing_library]: https://www.npmjs.com/package/@azure/core-tracing +[azure_monitor]: https://pypi.org/project/opentelemetry-azure-monitor/ +[zipkin]: https://zipkin.io/ +[our_open_telemetry_library]: https://pypi.org/project/azure-core-tracing-opentelemetry/ diff --git a/docs/client/troubleshooting.md b/docs/client/troubleshooting.md new file mode 100644 index 0000000000..fdce8295e4 --- /dev/null +++ b/docs/client/troubleshooting.md @@ -0,0 +1,34 @@ +# Troubleshooting + +## Error Handling + +Our generated clients raise errors when a service cal returns an undesired error code. + +A very basic form of error handling looks like this + +```js +import { DefaultAzureCredential } from "@azure/identity"; +import { PetsClient } from "@azure/pets"; + +let client: PetsClient; + +client = new PetsClient(new DefaultAzureCredential()); +try { + const dog = await client.getDog(); +} catch (err) { + console.log(err.statusCode); +} +``` + +## Logging + +Enabling logging may help uncover useful information about failures. In order to see a log of HTTP requests and responses, set the `AZURE_LOG_LEVEL` environment variable to `info`. + +``` +export AZURE_LOG_LEVEL=info +``` + +For more detailed instructions on how to enable logs, you can look at the [@azure/logger package docs][logger-docs] + + +[logger_docs]: https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/core/logger \ No newline at end of file diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000000..36853b7767 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,16 @@ +# FAQ + +1. What version of AutoRest Typescript should I use? + + CURRENTLY NO AUTOREST TYPESCRIPT ION NPM + + We highly recommend you use the latest AutoRest Typescript version published to [npm][autorest_npm]. The latest version + is the default if you use flag `--typescript`, though you may need to run an `autorest --reset` if it seems + the latest version is not being grabbed. + + If you *really* want to use an older version of AutoRest Typescript, + you can specify the version with the flag `--use`, i.e. `--use=@autorest/typescript@x.x.x`. + + + +[autorest_npm]: https://www.npmjs.com/package/@autorest/python \ No newline at end of file diff --git a/docs/generate/troubleshooting.md b/docs/generate/troubleshooting.md new file mode 100644 index 0000000000..e60ace5888 --- /dev/null +++ b/docs/generate/troubleshooting.md @@ -0,0 +1,38 @@ +# Troubleshooting + +## Generation Errors + +There are two broad kinds of errors you can run into when generating: one kind is thrown earlier in the AutoRest pipeline and has to do with malformed swaggers (see [our main docs][main_docs] for more information). The other kind is thrown by the Typescript generator itself. + +The general AutoRest errors are thrown like this + +``` +FATAL: Error: Enum types of 'object' and format 'undefined' are not supported. Correct your input (HdiNodeTypes). + Error: Plugin modelerfour reported failure. +``` + +While the Typescript generator throws Typescript errors, such as: + +``` +ERROR: [main.Process:52] Typescript generator raised an exception +Traceback (most recent call last): + ... +Unexpected value type: FakeValueType + Error: Plugin codegen reported failure. +``` + +Both of these issues should give you enough information to fix the error. If not, please let us know in either the [main repo][autorest_issues], or in the [Typescript repo][autorest_typescript_issues]. Also let us know if you believe +there are erroneous errors being thrown. + +## Debugging + +Our [main docs][main_debugging] show you how to pass in flags (`--verbose` / `--debug`) to get more debugging logs for your AutoRest calls. + +If you'd like to actually debug through our code, you need to first clone the `v6` branch of our [repo][repo], then include flag `--typescript.debugger` on our command line. You should now be able to step through the Typescript generator's code base. + + +[main_docs]: https://github.com/Azure/autorest/tree/master/docs/generate/troubleshooting.md +[autorest_issues]: https://github.com/Azure/autorest/issues +[autorest_typescript_issues]: https://github.com/Azure/autorest.typescript/issues +[main_debugging]: https://github.com/Azure/autorest/tree/master/docs/generate/troubleshooting.md#debugging +[repo]: https://github.com/Azure/autorest.typescript/tree/v6 \ No newline at end of file diff --git a/docs/images/logo.png b/docs/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5ed86d23c297aa485adee8e66666bec43a14bf2d GIT binary patch literal 20582 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 Migrating to Latest AutoRest + +See the [main docs][main_docs] for changes in versioning and flags, this section focuses on how the generated code differs. + +## Breaking Changes + +TODO + +## New Features + +TODO diff --git a/docs/readme.md b/docs/readme.md new file mode 100644 index 0000000000..1f8d668241 --- /dev/null +++ b/docs/readme.md @@ -0,0 +1,37 @@ +# AutoRest Typescript Documentation + +These documents are Typescript-specific, see [our main docs][main_docs] for more general information + + +1. Generating Typescript Clients with AutoRest + - How do I generate code? Main documents are [here][main_generate], while here are the [typescript-specific docs][typescript_generate] + +2. Using Your Generated Typescript Client + - How do I [use my Typescript client][typescript_client] now that I've generated it? Main docs are [here][main_client] + +3. Migrating from AutoRest 2.0 to 3.0 + - I have old generated code using the previous version of AutoRest. How do I upgrade my code? Main docs [here][main_migrate], Typescript-specific docs [here][typescript_migrate] + +4. Developing with AutoRest + - How do I generate or contribute to AutoRest in [dev mode][typescript_dev] Main docs [here][main_dev] + +5. Samples + - [Sample][sample] readmes and generated code for common scenarios. + +6. [FAQ][faq] + +7. [Troubleshooting][troubleshooting] + + +[main_docs]: https://github.com/Azure/autorest/tree/master/docs +[main_generate]: https://github.com/Azure/autorest/tree/master/docs/generate/readme.md +[typescript_generate]: ./generate/readme.md +[typescript_client]: ./client/readme.md +[main_client]: https://github.com/Azure/autorest/tree/master/docs/generate/client.md +[main_migrate]: https://github.com/Azure/autorest/tree/master/docs/migrate/readme.md +[typescript_migrate]: ./migrate/readme.md +[typescript_dev]: ./developer/readme.md +[main_dev]: https://github.com/Azure/autorest/tree/master/docs/dev/readme.md +[sample]: ./samples/readme.md +[faq]: ./faq.md +[trobleshooting]: ./troubleshooting.md diff --git a/docs/samples/readme.md b/docs/samples/readme.md new file mode 100644 index 0000000000..07f2a1563b --- /dev/null +++ b/docs/samples/readme.md @@ -0,0 +1,16 @@ +# Sample Python Generation + +Here are our samples for common generation scenarios + + +| Scenario | README | Generated Code +|------------------|-------------|------------- +|Generating most basic | [readme.md][basic_readme] | [generated][basic_generated] +|Generating [management plane][mgmt] | [readme.md][mgmt_readme] | [generated][mgmt_generated] + + +[basic_readme]: ./specification/basic/readme.md +[basic_generated]: ./specification/basic/generated +[mgmt]: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/control-plane-and-data-plane#control-plane +[mgmt_readme]: ./specification/management/readme.md +[mgmt_generated]: ./specification/management/generated \ No newline at end of file diff --git a/docs/samples/specification/basic/readme.md b/docs/samples/specification/basic/readme.md new file mode 100644 index 0000000000..a7a235762e --- /dev/null +++ b/docs/samples/specification/basic/readme.md @@ -0,0 +1,10 @@ +# Sample Basic Generation + +### Settings + +``` yaml +input-file: ../../../../node_modules/@microsoft.azure/autorest.testserver/swagger/head.json +package-name: @azure/basic-sample +license-header: MICROSOFT_MIT_NO_VERSION +package-version: 0.1.0 +``` \ No newline at end of file diff --git a/docs/samples/specification/management/readme.md b/docs/samples/specification/management/readme.md new file mode 100644 index 0000000000..19919829ad --- /dev/null +++ b/docs/samples/specification/management/readme.md @@ -0,0 +1,16 @@ +# Sample Management Generation + +Use the flag `--azure-arm` to specify you want to generate [management plane][mgmt] code. For more information, see our [flag index][flag_index] + +### Settings + +``` yaml +input-file: ../../../../node_modules/@microsoft.azure/autorest.testserver/swagger/head.json +package-name: @azure/mgmt-sample +license-header: MICROSOFT_MIT_NO_VERSION +azure-arm: true +``` + + +[mgmt]: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/control-plane-and-data-plane#control-plane +[flag_index]: https://github.com/Azure/autorest/tree/master/docs/generate/flags.md \ No newline at end of file From 2152ddc7aa69734044562814f07e8db7dd21dbf8 Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Thu, 7 Jan 2021 15:00:21 -0500 Subject: [PATCH 2/2] address jose's comments --- docs/client/initializing.md | 8 ++---- docs/client/models.md | 10 +++---- docs/client/operations.md | 40 +++++--------------------- docs/client/tracing.md | 20 ++++++------- docs/client/troubleshooting.md | 4 +-- docs/faq.md | 2 +- docs/readme.md | 1 - docs/{generate => }/troubleshooting.md | 0 8 files changed, 25 insertions(+), 60 deletions(-) rename docs/{generate => }/troubleshooting.md (100%) diff --git a/docs/client/initializing.md b/docs/client/initializing.md index ea873938a4..b51481627c 100644 --- a/docs/client/initializing.md +++ b/docs/client/initializing.md @@ -22,9 +22,7 @@ Next, on to initialization. Your constructor can take any number of parameters. ```js import { PetsClient } from "@azure/pets"; -let client: PetsClient; - -client = new PetsClient(); +const client: PetsClient = new PetsClient(); ``` If you generate with flag `--add-credentials`, your client wil be generated with an [Azure Active Directory (AAD) token credential][aad_authentication]. We always recommend @@ -37,9 +35,7 @@ As an installation note, the [`@azure/identity`][azure_identity_library] library import { DefaultAzureCredential } from "@azure/identity"; import { PetsClient } from "@azure/pets"; -let client: PetsClient; - -client = new PetsClient(new DefaultAzureCredential()); +const client: PetsClient = new PetsClient(new DefaultAzureCredential()); ``` diff --git a/docs/client/models.md b/docs/client/models.md index 5c58845939..6d8dddc8cf 100644 --- a/docs/client/models.md +++ b/docs/client/models.md @@ -2,19 +2,17 @@ ## General -Models and enums are generated in the `models` namespace. So, say you are using package `@azure/pets`. To access model `Dog`, you would use the following code +Models and enums are generated in the `models` module. So, say you are using package `@azure/pets`. To access model `Dog`, you would use the following code snippet ```js -import { Dog } from "@azure/pets.models"; +import { Dog } from "@azure/pets"; ``` Enums are also listed in the `models` namespace, so say you have enum class `DogTypes`. To access the `Dalmation` enum, your code would look like ```js -import { DogTypes } from "@azure/pets.models"; +import { DogTypes } from "@azure/pets"; -let dogType: str; - -dogType = DogTypes.Dalmation; +const dogType: str = DogTypes.Dalmation; ``` diff --git a/docs/client/operations.md b/docs/client/operations.md index c310e64995..e3385f7f7f 100644 --- a/docs/client/operations.md +++ b/docs/client/operations.md @@ -1,6 +1,6 @@ # Calling Operations with Your Typescript Client -AutoRest provides both synchronous and asynchronous method overloads for each service operation. +AutoRest provides asynchronous method overloads for each service operation. Depending on your swagger definition, operations can be accessed through operation groups (TODO: link to swagger docs) on the client, or directly on the client. @@ -14,22 +14,13 @@ itself, i.e. `client.getDog()`. ## Regular Operations -### Sync Operations - -We don't generate sync operations, all of our operations are async. - -### Async Operations - -When calling our async operations, we use our async client, which is in a different module. Following the [example above](#sync-operations Sync Operations), -our call to `getDog` looks like this: +When calling our async operations, we go through our client ```js import { DefaultAzureCredential } from "@azure/identity"; import { PetsClient } from "@azure/pets"; -let client: PetsClient; - -client = new PetsClient(new DefaultAzureCredential()); +const client: PetsClient = new PetsClient(new DefaultAzureCredential()); const dog = await client.getDog(); ``` @@ -41,12 +32,6 @@ In concurrence with our [typescript guidelines][poller_guidelines], all of our l For our example, we will use the long running operation generated from [this][example_swagger] swagger. Let's say we generated this swagger with package name `@azure/lro`. -### Sync Long Running Operations - -We don't generate sync operations, all of our operations are async. - -### Async Long Running Operations - By default, our async long running operations return an [`Poller`][poller] polling object, though there [are ways][custom_poller] of changing this. Calling `.pollUntilDone()` on the poller will wait until the long running operation finishes then return the final result. @@ -54,12 +39,9 @@ on the poller will wait until the long running operation finishes then return th import { DefaultAzureCredential } from "@azure/identity"; import { Product, PollingPagingExampleClient } from "@azure/lro"; -let client: PollingPagingExampleClient; -let inputProduct: Product; - -client = new PollingPagingExampleClient(new DefaultAzureCredential()); +const client: PollingPagingExampleClient = new PollingPagingExampleClient(new DefaultAzureCredential()); -inputProduct = { +const inputProduct: Product = { id: 1; name: "My Polling example" }; @@ -75,13 +57,7 @@ is initially called. For our example, we will use the long running operation generated from [this][example_swagger] swagger. Let's say we generated this swagger with package name `@azure/paging`. -### Sync Paging Operations - -We don't generate sync operations, all of our operations are async. - -### Async Paging Operations - -By default, our sync paging operations return an [`PagedAsyncIterableIterator`][paged_async_iterable_iterator] pager. Since network calls aren't +By default, our async paging operations return an [`PagedAsyncIterableIterator`][paged_async_iterable_iterator] pager. Since network calls aren't made until starting to page, our generated operation is synchronous, and there's no need to wait the initial call to the function. Since network calls are made when iterating, we have to do async looping. @@ -89,9 +65,7 @@ we have to do async looping. import { DefaultAzureCredential } from "@azure/identity"; import { PollingPagingExampleClient } from "@azure/paging"; -let client: PollingPagingExampleClient; - -client = new PollingPagingExampleClient(new DefaultAzureCredential()); +const client: PollingPagingExampleClient = new PollingPagingExampleClient(new DefaultAzureCredential()); const pager = client.basicPaging(); for await (const product of pager) { diff --git a/docs/client/tracing.md b/docs/client/tracing.md index 32d8dff4cd..e4e0af4ad4 100644 --- a/docs/client/tracing.md +++ b/docs/client/tracing.md @@ -18,13 +18,13 @@ Since there is no explicit context you need to pass, you can create your usual O The following example uses the [Zipkin][zipkin] exporter. ```js -const tracing = require("@opencensus/nodejs"); -const { ZipkinTraceExporter } = require("@opencensus/exporter-zipkin"); -const { +import tracing from "@opencensus/nodejs"); +import { ZipkinTraceExporter } from "@opencensus/exporter-zipkin"; +import { setTracer, OpenCensusTracerWrapper, OpenCensusSpanWrapper -} = require("@azure/core-tracing"); +} from "@azure/core-tracing"; const tracer = tracing.start({ samplingRate: 1 }).tracer; @@ -46,17 +46,17 @@ tracer.startRootSpan({ name: "root" }, async (rootSpanEx) => { First step is to install our [`OpenTelemetry` library][our_open_telemetry_library]: -```python -pip install azure-core-tracing-opentelemetry +```bash +npm install --save @azure/core-tracing ``` Since there is no explicit context you need to pass, you can create your usual OpenTelemetry tracer and call the generated SDKs. The following example uses the [Zipkin][zipkin] exporter. ```js -const opentelemetry = require("@opentelemetry/core"); -const { BasicTracer, SimpleSpanProcessor } = require("@opentelemetry/tracing"); -const { ZipkinExporter } = require("@opentelemetry/exporter-zipkin"); -const { setTracer } = require("@azure/core-tracing"); +import opentelemetry from "@opentelemetry/core"; +import { BasicTracer, SimpleSpanProcessor } from "@opentelemetry/tracing"; +import { ZipkinExporter } = from "@opentelemetry/exporter-zipkin"; +import { setTracer } from "@azure/core-tracing"; const exporter = new ZipkinExporter({ serviceName: "azure-tracing-sample" diff --git a/docs/client/troubleshooting.md b/docs/client/troubleshooting.md index fdce8295e4..46176f6606 100644 --- a/docs/client/troubleshooting.md +++ b/docs/client/troubleshooting.md @@ -10,9 +10,7 @@ A very basic form of error handling looks like this import { DefaultAzureCredential } from "@azure/identity"; import { PetsClient } from "@azure/pets"; -let client: PetsClient; - -client = new PetsClient(new DefaultAzureCredential()); +const client: PetsClient = new PetsClient(new DefaultAzureCredential()); try { const dog = await client.getDog(); } catch (err) { diff --git a/docs/faq.md b/docs/faq.md index 36853b7767..0d71ccd1b7 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -2,7 +2,7 @@ 1. What version of AutoRest Typescript should I use? - CURRENTLY NO AUTOREST TYPESCRIPT ION NPM + CURRENTLY NO AUTOREST TYPESCRIPT ON NPM We highly recommend you use the latest AutoRest Typescript version published to [npm][autorest_npm]. The latest version is the default if you use flag `--typescript`, though you may need to run an `autorest --reset` if it seems diff --git a/docs/readme.md b/docs/readme.md index 1f8d668241..53dadb9d78 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -2,7 +2,6 @@ These documents are Typescript-specific, see [our main docs][main_docs] for more general information - 1. Generating Typescript Clients with AutoRest - How do I generate code? Main documents are [here][main_generate], while here are the [typescript-specific docs][typescript_generate] diff --git a/docs/generate/troubleshooting.md b/docs/troubleshooting.md similarity index 100% rename from docs/generate/troubleshooting.md rename to docs/troubleshooting.md