ADR-0021: Microsoft Graph SDK Choice — httpx + msal¶
Status¶
Accepted
Context¶
ID-127 adds a Microsoft Graph backend covering OneDrive (personal and business), SharePoint document libraries, and Teams files. Before writing the backend, the transport and auth-library choice has to be locked in. Three credible options exist:
- Direct REST via
httpx+msal. Call the Graph HTTP surface ourselves; use Microsoft's MSAL library for token acquisition and caching. msgraph-sdk(Kiota-generated). Microsoft's official Python SDK for Graph. Generated from the Graph OpenAPI description via Kiota. Async-only client. Transitive dependency onkiota-abstractions,kiota-http,kiota-authentication-azure, andazure-identity.Office365-REST-Python-Client. Third-party library that mixes Graph and legacy SharePoint REST patterns.
The surface we need is narrow: a dozen Graph endpoints covering item
metadata, children listing, range download via @microsoft.graph.downloadUrl,
small-file PUT /content, resumable upload sessions, async copy with
monitor-URL polling, and delete. The non-trivial work — upload-session
chunking with resume, async-operation polling, URL-expiry-mid-read
handling — is not carried by any of these SDKs; we have to write it
regardless.
httpx is already a runtime option in the project for the HTTP backend
extra. msal is Microsoft's supported auth library, lightweight,
stable, and used by azure-identity internally.
Decision¶
Build the backend on httpx (async client) plus msal for token
acquisition and cache serialization.
The graph optional extra installs httpx, msal, and
platformdirs (the latter used by the built-in GraphAuth for
resolving the MSAL token-cache path; see ADR-0022). The backend
constructs an httpx.AsyncClient internally and treats Graph as a
narrow REST surface with hand-written request helpers, pagination, and
error mapping.
msgraph-sdk is explicitly rejected. Office365-REST-Python-Client is
out of scope (legacy SharePoint REST is not a goal — see RFC-0010).
Consequences¶
- Narrow dependency footprint.
httpx+msalis lighter thanmsgraph-sdk+ Kiota runtime +azure-identity. The existing HTTP backend already pullshttpx, so users combining the two pay for it once. - Full control of request layer. Error mapping, retry,
Retry-Afterhandling, and monitor-URL polling are written directly againsthttpx.Responseand raw status codes. No Kiota-shaped abstractions in the way. - Async-native fit.
httpx.AsyncClientis the transport; the backend implementsAsyncBackendper ADR-0012. No forced adaptation layer. - Maintenance responsibility stays with us. The cost of not using
msgraph-sdkis that we maintain the request layer ourselves as the Graph surface evolves. The surface touched here is stable (drives/items endpoints are part of the v1.0 API), so ongoing churn is expected to be low. - Future revisit point. If the backend later grows to cover
a materially broader Graph surface (mail, calendar, Teams messages,
groups), re-evaluating
msgraph-sdkbecomes reasonable. A new ADR would supersede this one.
References¶
- RFC-0010: Microsoft Graph Backend (SDK evaluation section)
sdd/specs/044-graph-backend.md- ADR-0012: Async Store / Backend API
httpxproject: https://www.python-httpx.org/- MSAL for Python: https://learn.microsoft.com/entra/msal/python/
- Microsoft Graph v1.0 reference: https://learn.microsoft.com/graph/api/overview