[DPS] Migrate dataplane API to typespec (stable/2021-10-01 + preview/2025-07-01-preview)#42175
Conversation
Next Steps to Merge✅ All automated merging requirements have been met! To get your PR merged, see aka.ms/azsdk/specreview/merge.Comment generated by summarize-checks workflow run. |
cab0ae9 to
1b697d5
Compare
API Change CheckAPIView identified API level changes in this PR and created the following API reviews
Comment generated by After APIView workflow run. |
Breaking Change Analysis — commit ef24753The BreakingChange CI flagged 4 violations when comparing the TypeSpec-generated
Remaining (2 unavoidable): The |
…e + preview) Migrates the Azure IoT Hub Device Provisioning Service data-plane REST API from handwritten Swagger 2.0 to TypeSpec for both device and service APIs across stable (2021-10-01) and preview (2025-07-01-preview) versions. TypeSpec source: - device/: runtime registration API - service/: enrollment management API Key changes: - Single TypeSpec source emits both stable and preview swagger simultaneously - Preview-only features gated with @added(Versions.v2025_07_01_preview) - LRO 202 responses explicitly modeled with retry-after and Location headers - Free-form JSON fields use Record<unknown> to preserve additionalProperties behavior - Default values restored: provisioningStatus, iotEdge, reprovision policy flags - Query response headers documented: x-ms-continuation, x-ms-item-type, x-ms-max-item-count - Added 4 new device preview examples missing from original swagger - Fixed azure-arm: true to false in readme.csharp.md - Added clientLocation for registerDeviceAndIssueCertificate in device/client.tsp No service-side changes. All wire contracts preserved. Old SDKs remain compatible. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ggers
- device/routes.tsp: rename body param to 'deviceRegistration' in RegisterDeviceAndIssueCertificate
- device/examples/2025-07-01-preview: fix 'title' fields in MaximumSet/MinimumSet source example files
- service/routes.tsp: wrap runBulkOperation body as named 'bulkOperation' param (both stable + preview ops)
- service/models.tsp: TwinCollection uses Record<{}> for additionalProperties; add @minlength(1) to 8 string properties
- Regenerate preview/2025-07-01-preview/device.json and service.json, stable/2021-10-01/service.json
- TYPESPEC-MIGRATION.md: correct Record<unknown> references to Record<{}>; update additionalProperties table
All 12 validation checks pass (paths, operationIds, HTTP methods, response codes, required fields,
x-ms-examples count/refs/keys, body params, enum values, example titles, JSON validity).
0 deleted files. No breaking changes vs origin/main swaggers.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- device/models.tsp: remove extra blank lines in X509CertificateInfo - service/models.tsp: remove extra blank lines in X509CertificateInfo - service/routes.tsp: expand inline anonymous objects to multi-line form These are cosmetic whitespace changes only; no swagger output changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…a-plane migration Changes: - Add root tspconfig.yaml stub required by tsv FlavorAzure and LinterRuleset CI rules - Add SdkTspConfigValidation suppression for root tspconfig.yaml in suppressions.yaml - Fix payload fields: use Record<unknown> (matches original object schema) with bad-record-type suppression to avoid breaking additionalProperties type restriction - Add @minlength(1) back to 8 service fields (consistent with original preview swagger; non-breaking improvement for stable - server always rejected empty strings) - Add #suppress directives and doc comments for all TypeSpec linter compliance - Regenerate all 4 swagger files (stable/preview x device/service) - Update TYPESPEC-MIGRATION.md: document minLength stable/preview alignment Validation results: - device-stable: functionally equivalent (CLEAN) - service-stable: functionally equivalent + minor minLength additions (logically correct) - device-preview: functionally equivalent (CLEAN) - service-preview: functionally equivalent (CLEAN) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…fix preview example api-versions - tsp format fixes: correct 2-space indentation in service/routes.tsp and device/routes.tsp - service/models.tsp: remove @minlength(1) from 8 fields to fix Swagger BreakingChange CI - Regenerate stable/2021-10-01/service.json and preview/service.json without minLength - Remove csr from DeviceRegistrationResult in OperationStatusLookup preview example - All 31 preview examples already have api-version updated to 2025-07-01-preview Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…view example api-versions to 2025-07-01-preview, remove invalid csr from response example bodies - Remove @minlength(1) from device/models.tsp RegistrationOperationStatus.operationId - Regenerate stable/2021-10-01/device.json and preview/2025-07-01-preview/device.json - Fix api-version in all 32 preview examples that still had '2021-10-01' - Remove 'csr' from RuntimeRegistration response bodies (not valid on DeviceRegistrationResult schema)
…rvice APIs - Fix 30 service/examples/2025-07-01-preview files: api-version 2021-10-01 -> 2025-07-01-preview - Regenerated preview/2025-07-01-preview/examples/service (30 files) from corrected sources - Remove csr from device/examples/2025-07-01-preview DeviceRegistrationStatusLookup + OperationStatusLookup MaximumSet sources - TSV: device/ and service/ source examples now match compiled outputs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…/ sub-projects Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sions Suppressions are matched against the tspconfig.yaml path, not the folder. Use ./device/tspconfig.yaml and ./service/tspconfig.yaml. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
All 132 generated and example JSON files formatted with prettier to fix Swagger PrettierCheck CI failure. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restores the minLength: 1 constraint on RegistrationOperationStatus.operationId that was present in the original swagger but missing from the TypeSpec migration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… constraints Apply @removed/@renamedFrom/@added pattern to 8 properties that have minLength:1 in preview/2025-07-01-preview but not in stable/2021-10-01: - IndividualEnrollment.registrationId - EnrollmentGroup.enrollmentGroupId - CustomAllocationDefinition.webhookUrl / apiVersion - BulkEnrollmentOperationError.registrationId / errorStatus - BulkEnrollmentGroupOperationError.enrollmentGroupId / errorStatus Resolves ConstraintChanged (1036) CI failures in preview-svc without introducing new constraints on the stable swagger. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment 1: Rename RuntimeRegistrationOperationGroup -> RuntimeRegistration so auto-generated operationIds match existing @operationid values; remove now- redundant @operationid decorators and their paired #suppress no-openapi. Comment 2: Fix LRO pattern - operationStatusLookup is the polling target, not an LRO initiator. Remove x-ms-long-running-operation extension from operationStatusLookup. Add @pollingOperation to registerDeviceAndIssueCertificate (preview) and @lroStatus/@lroSucceeded/@lroFailed decorators to EnrollmentStatus and DeviceRegistrationResult.status to satisfy Azure.Core LRO requirements. Regenerate stable and preview swaggers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- client.tsp: update 4 @@clientLocation refs from RuntimeRegistrationOperationGroup to RuntimeRegistration - models.tsp: add @lroStatus decorator to RegistrationOperationStatus.status field - routes.tsp: suppress polling-operation-no-status-monitor on operationStatusLookup (DPS non-standard LRO pattern) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lientLocation) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add suppressions block to readme.md covering pre-existing API design violations in device.json (6) and service.json (39) flagged as new by LintDiff due to the TypeSpec migration. Rules suppressed: OperationId, PutInOperationName, ParameterOrder, PathParameterSchema, LroHeaders, ErrorResponse (both files), OperationIdNounConflictingModelNames, PaginationResponse, EnumInsteadOfBoolean, AdditionalPropertiesObject (service.json). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add PathParameterSchema and SummaryAndDescriptionMustNotBeSame for service.json, and GetInOperationName, PutPath, PutRequestResponseScheme for device.json. All are pre-existing API design patterns maintained for backward compatibility. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ation/bulkOperation -> body
Body parameter rename in service/routes.tsp caused mismatch between swagger
param name ('body') and example parameter keys (old TypeSpec param names).
Updated 24 source example files in service/examples/ and regenerated 24
output copies in stable/2021-10-01/examples/ and preview/2025-07-01-preview/examples/.
Validation:
- oav validate-spec: passes on all 4 swagger files (0 errors)
- oav validate-example: passes on all 4 swagger files (0 errors)
- All example files valid JSON
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e/routes.tsp The request header parameters for x-ms-max-item-count were still typed as int32 in three query operations (IndividualEnrollment_Query, EnrollmentGroup_Query, DeviceRegistrationState_Query). The response model (ServiceQueryResponse.xMsMaxItemCount) was already corrected to int64 in a prior commit, but the inline request params in routes.tsp were missed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ode), int32 (not int64) The BreakingChange CI compares TypeSpec-generated stable/2021-10-01/service.json against the same file in main. The stable swagger in main uses: - 'format': 'int32' for x-ms-max-item-count (not int64) - enum name 'OperationMode' (not BulkEnrollmentMode) The previous preview swagger (referenced in mccoyp review) had different values, but the stable swagger had int32/OperationMode. Since TypeSpec generates both stable and preview from the same source, we align to the stable values to eliminate 2 of the 4 breaking changes. Only the unavoidable ReferenceRedirection BCs remain (TypeSpec always extracts named type definitions; inline enums not supported). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ef24753 to
affb027
Compare
…ody params - Fixed 5 If-Match header params with explicit wire name - Added @renamedFrom decorators for 6 body params to restore stable SDK names - Reverted post-processing on service.json (committed raw tsp compile output) - Regenerated stable/2021-10-01/service.json and preview/2025-07-01-preview/service.json
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
25fb2ba to
c9b20de
Compare
Rename 'body' parameter key in example files to match service.json: - IndividualEnrollment_CreateOrUpdate: body -> enrollment - IndividualEnrollment_Query: body -> querySpecification - IndividualEnrollment_RunBulkOperation: body -> bulkOperation - EnrollmentGroup_CreateOrUpdate: body -> enrollmentGroup - EnrollmentGroup_Query: body -> querySpecification - EnrollmentGroup_RunBulkOperation: body -> bulkOperation Fixes Swagger ModelValidation CI (REQUIRED_PARAMETER_EXAMPLE_NOT_FOUND) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Rename body param keys to match TypeSpec-generated swagger names: enrollment, enrollmentGroup, querySpecification, bulkOperation - Rename response 200 body key from semantic name back to 'body' (required by OAV/ModelValidation tooling) - Affects 12 stable/2021-10-01 example files Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…es for stable API Update TypeSpec source examples (service/examples/2021-10-01/) and recompile: - Rename body param key to semantic names in source examples: - enrollment (IndividualEnrollment CreateOrUpdate) - enrollmentGroup (EnrollmentGroup CreateOrUpdate) - querySpecification (Query operations) - bulkOperation (RunBulkOperation operations) - Regenerate stable/2021-10-01/examples/ via tsp compile + prettier - Output examples now exactly match tsp compile output, fixing TypeSpec Validation CI - Param keys also match service.json, fixing Swagger ModelValidation CI Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR Status Update — HEAD
|
| Status | Check |
|---|---|
| ✅ | TypeSpec Validation |
| ✅ | Swagger ModelValidation |
| ✅ | Swagger LintDiff |
| ✅ | Swagger SemanticValidation |
| ✅ | Swagger PrettierCheck |
| ✅ | Swagger Avocado |
| ✅ | Breaking Change (Cross-Version) |
| ✅ | SDK Generation — .NET, Go, Java, JavaScript, Python |
| ✅ | TypeSpec Requirement, TypeSpec APIView, Swagger APIView |
| ✅ | SpellCheck, Sdk Suppressions, Protected Files, CLA |
| ⏭️ | TypeSpec Migration Validation (skipped — expected) |
| ❌ | Swagger BreakingChange — 13 TypeSpec migration artifacts (see below) |
Swagger BreakingChange Failure Analysis
All 13 errors are inherent to TypeSpec migration — no actual API contract changes. Breakdown:
| Code | Count | Root Cause |
|---|---|---|
ReferenceRedirection |
4 | $ref path changed: #/parameters/ApiVersionParameter → #/parameters/Azure.Core.Foundations.ApiVersionParameter — TypeSpec emitter naming convention |
DefaultValueChanged |
3 | api-version parameter default value emitted differently by TypeSpec vs. hand-written swagger |
ParameterLocationHasChanged |
2 | api-version moved from global client param (method=false) to method-level param (method=true) — TypeSpec generation pattern |
ChangedParameterOrder |
4 | TypeSpec emits parameters in a different order than the original hand-written swagger (bulkOperation, id, x-ms-max-item-count, x-ms-continuation) |
None of these represent actual wire-format or behavioral changes to the API.
Open Review Thread
One review thread is technically unresolved in GitHub UI (service/routes.tsp line 14 — removing "OperationGroup" interface suffix). @mccoyp has acknowledged it cannot be done due to TypeSpec name collision constraints and stated "I think the current solution is fine considering the constraints." — resolved in substance.
Next Steps to Merge
PublishToCustomerslabel — acknowledges this PR targetsmainand the APIs will be released to Azure customers.BreakingChangeReviewRequiredapproval — follow the process at aka.ms/brch with justification: All 13 breaking change flags are TypeSpec migration artifacts (parameter naming/ordering/location differences between hand-written and TypeSpec-generated swagger). No wire-format or behavioral changes to the API.
mccoyp
left a comment
There was a problem hiding this comment.
Aside from this single breaking change, everything else is looking good to me after a thorough review! One lingering question, just to be super sure, is whether the x-ms-long-running-operation: true extension for the operation status lookup was incorrect/unintentional in the stable device.json:
I assume it's not an LRO, and the updated spec reflects this, but just wanted to get explicit confirmation
- Fix readOnly on DeviceRegistrationState.status/substatus (service) - Fix readOnly on DeviceRegistrationResult.status/substatus (device) - Version-split operationStatusLookup to fix x-ms-long-running-operation: stable keeps LRO, preview omits it (matching original swagger baselines) - Add new CredentialEnrollmentGroup and related models to service TypeSpec Zero real breaking changes vs original stable (2021-10-01) and preview (2025-07-01-preview) swagger baselines. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ioningservices-dataplane
Thread Azure#2 resolution: use @renamedFrom versioning decorator to consolidate the duplicate OperationMode enum (previously inline-defined in preview) with BulkEnrollmentMode. Both BulkEnrollmentOperation.mode and BulkEnrollmentGroupOperation.mode now reference BulkEnrollmentMode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Final status — breaking change analysis + review thread resolutionReview threads (all resolved)
Validation suite (all passing locally)
Breaking change analysis vs pre-migration baselineRan Stable
Preview
ConclusionReal semantic breaking changes: effectively zero. All oad findings are either:
The |
…ument @renamedFrom The TYPESPEC-MIGRATION.md incorrectly described the BulkEnrollmentMode rename as 'preview aligned with stable name OperationMode'. In fact the opposite is true: the original stable Swagger used OperationMode and the original preview Swagger used BulkEnrollmentMode. The TypeSpec source uses @renamedFrom(Versions.v2025_07_01_preview, 'OperationMode') on union BulkEnrollmentMode so that both original names are preserved exactly in their respective emitted Swaggers. Also adds Post-Conversion Fix Azure#9 describing the @renamedFrom decorator and updates the property-level change table to reflect per-version enum naming. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@mccoyp — explicit confirmation on the The original stable #suppress "@azure-tools/typespec-azure-core/no-openapi" "Migration from Swagger: preserving x-ms-long-running-operation extension on polling GET for compatibility"
#suppress "@azure-tools/typespec-azure-core/polling-operation-no-status-monitor" "The DPS device API uses a non-standard LRO pattern; status field is on the nested RegistrationOperationStatus body"
@extension("x-ms-long-running-operation", true)Why keep it:
If you'd prefer we drop the extension on the status-lookup GET in the preview version only (cleaner semantics, no stable break), happy to do that — just let me know. |
mccoyp
left a comment
There was a problem hiding this comment.
Just one small suggestion for the TSP migration doc -- which is a great addition, by the way! -- and otherwise things look great
…line union style Addresses @mccoyp review feedback on TYPESPEC-MIGRATION.md:101. The section previously described named `RegistrationOperationStatus200 | RegistrationOperationStatus202` model aliases, but current LRO style emits the 200/202 responses as inline anonymous unions directly on each operation. Updated the snippet and surrounding context to reflect actual source. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Data Plane API Specification Update Pull Request
Tip
Overwhelmed by all this guidance? See the
Getting helpsection at the bottom of this PR description.PR review workflow diagram
Please understand this diagram before proceeding. It explains how to get your PR approved & merged.
API Info: The Basics
Most of the information about your service should be captured in the issue that serves as your API Spec engagement record.
Is this review for (select one):
Change Scope
specification/deviceprovisioningservices/data-plane/DeviceProvisioningServices/stable/2021-10-01/andpreview/2025-07-01-preview/specification/deviceprovisioningservices/data-plane/DeviceProvisioningServices/device/(new TypeSpec source)specification/deviceprovisioningservices/data-plane/DeviceProvisioningServices/service/(new TypeSpec source)specification/deviceprovisioningservices/data-plane/DeviceProvisioningServices/stable/2021-10-01/device.jsonspecification/deviceprovisioningservices/data-plane/DeviceProvisioningServices/stable/2021-10-01/service.jsonspecification/deviceprovisioningservices/data-plane/DeviceProvisioningServices/preview/2025-07-01-preview/device.jsonspecification/deviceprovisioningservices/data-plane/DeviceProvisioningServices/preview/2025-07-01-preview/service.jsonspecification/deviceprovisioningservices/data-plane/DeviceProvisioningServices/TYPESPEC-MIGRATION.mdViewing API changes
For convenient view of the API changes made by this PR, refer to the URLs provided in the table in the
Generated ApiViewcomment added to this PR.Breaking change summary: Zero breaking changes. See
TYPESPEC-MIGRATION.mdin this PR for the full per-file diff analysis confirming all paths, operations, response codes, headers, required fields, and error schemas are identical.Suppressing failures
Suppressions are defined in
suppressions.yaml(carried over from original swagger). No new suppressions added.Release planner
This is a TypeSpec migration PR — no new API surface is being added. No SDK release plan required.
How to build