Summary
Webex recently published all their public API specs at webex/webex-openapi-specs — 9 OpenAPI JSON files covering every Webex service family, updated nearly every day via an automated pipeline. We'd like to use those specs to auto-generate a thin network layer inside this SDK so it can never fall behind the Webex API again.
This is an RFC (Request for Comments). We have a full design spec and want community input before writing any code.
The problem today
The SDK's 22 API wrapper files are entirely hand-maintained. When Webex adds or changes a parameter, someone has to notice and manually update the code. In practice, that doesn't always happen quickly — or at all.
Known drift that already exists right now:
| File |
Issue |
events.py |
Missing serviceType parameter; resource enum values are stale (docs say "messages, memberships" — spec shows 8+ values) |
rooms.py |
ECM folder linking (/room/linkedFolders) not in SDK |
| — |
HDS (Hosted Data Services) endpoints not in SDK |
| — |
BroadWorks, Cloud Calling, Contact Center, Device, UCM, Wholesale APIs have zero SDK coverage despite being in the specs |
And the webex/webex-openapi-specs repo gets ~daily commits, so this gap only grows.
The proposed solution: a three-layer architecture
Rather than replacing the hand-written code, we'd add a generated layer underneath it:
┌──────────────────────────────────────────────────────┐
│ api/messages.py, api/rooms.py, ... CUSTOM LAYER │
│ Unchanged public API. All the Pythonic ergonomics: │
│ pagination, type checking, file uploads, aliases │
│ Calls into ↓ │
├──────────────────────────────────────────────────────┤
│ _generated/messaging.py, _generated/meeting.py, ... │
│ GENERATED NETWORK LAYER │
│ One function per OpenAPI operationId. Knows every │
│ endpoint URL, method, and parameter. Regenerated │
│ automatically when the specs change. │
│ Calls into ↓ │
├──────────────────────────────────────────────────────┤
│ restsession.py UNCHANGED │
│ Auth, rate limiting, RFC5988 pagination │
└──────────────────────────────────────────────────────┘
What changes
- A new
generator/openapi_to_generated.py script reads the Webex OpenAPI JSON files and writes webexpythonsdk/_generated/*.py
- Each generated file contains one function per API operation — it knows the endpoint URL, which HTTP method to use, and which parameters go where
- The existing
api/*.py classes delegate their HTTP calls into the generated layer instead of calling self._session directly
- A scheduled GitHub Actions workflow fetches the latest specs daily and opens a PR if anything changed
What stays exactly the same
Every part of the SDK users interact with today is preserved:
- All public method signatures, parameter names, and defaults
@generator_container reusable pagination
- Runtime type checking via
check_type()
- Local file → multipart upload in
messages.create()
AdaptiveCard object handling in messages.create()
**request_parameters escape hatch on every method
messages.edit alias, people.me(), rooms.get_meeting_info(), messages.list_direct() — all kept
What gets better immediately
- New Webex parameters appear in the generated layer on the next daily sync and flow through
**request_parameters to callers right away — no SDK change needed
- New endpoints become accessible as soon as specs update
- The daily sync PR gives maintainers a clear diff of what Webex changed
What a generated function looks like
# webexpythonsdk/_generated/messaging.py
# AUTO-GENERATED from webex-messaging.json — do not edit
def _compact(**kw):
return {k: v for k, v in kw.items() if v is not None}
# GET /messages → paginated list
def list_messages(session, roomId, parentId=None, mentionedPeople=None,
before=None, beforeMessage=None, max=50, **extra):
params = _compact(roomId=roomId, parentId=parentId,
mentionedPeople=mentionedPeople, before=before,
beforeMessage=beforeMessage, max=max, **extra)
return session.get_items('messages', params=params)
# GET /events → 'from' is a Python keyword, renamed to from_
def list_events(session, resource=None, type=None, actorId=None,
from_=None, to=None, max=None, serviceType=None, **extra):
params = _compact(resource=resource, type=type, actorId=actorId,
to=to, max=max, serviceType=serviceType, **extra)
if from_ is not None:
params['from'] = from_
return session.get_items('events', params=params)
And the custom layer on top stays nearly identical to today — it just swaps self._session.get_items(...) for _gen.list_messages(self._session, ...).
Testing approach
The plan includes a strict no-regression testing strategy:
- Before touching any code: snapshot every public method signature and run the full integration test suite, saving both as baseline documents
- New unit tests (no credentials needed): mock-based tests that verify the generated layer builds the right HTTP calls and that the custom layer delegates correctly, preserves the generator container behavior, handles file uploads, converts AdaptiveCards, etc.
- Phase-by-phase: refactor one API file at a time, run unit tests after each, integration tests at the end
- Final gate: public API surface diff must be empty — zero method signatures changed
Full design spec
A detailed implementation spec lives on the working branch:
docs/openapi-integration-spec.md
It covers the full phase-by-phase plan, the generator design, the refactoring order for all 22 API files, the complete test matrix, the CI workflow design, a traceability table mapping every existing behavior to its test, and a rollback plan.
Questions for the community
We want to hear from you before starting implementation:
-
Does this approach make sense to you? The generated layer is a new internal concept — does it feel like the right separation of concerns, or does it add unwanted complexity?
-
Are there any existing behaviors we haven't accounted for? If you use the SDK in ways that rely on something subtle in the current implementation, please share — we want to catch it before the refactor, not after.
-
Which new API families should we prioritize? Cloud Calling, Contact Center, BroadWorks, Device, UCM, Wholesale — all currently have zero SDK coverage. What would be most useful to expose first?
-
Meetings generator: The meetings family already has a custom YAML-based generator. Should we migrate it to the OpenAPI generator, or keep both pipelines running in parallel?
-
Generated files in the repo: Should _generated/*.py be committed to the repo (easy to read the current state, reviewable diffs in PRs) or always built from specs at install/build time (smaller repo, no stale generated code)? We lean toward committing them for transparency, but want input.
-
Any concerns about the daily sync PR cadence? If Webex is updating specs nearly every day, that's potentially a lot of automated PRs. Should we batch them (e.g., weekly) or only open a PR when the generated Python output actually changes (not just the raw JSON)?
How to contribute
- Comment below with feedback, concerns, or use cases we should account for
- Review the full spec and flag anything that looks wrong
- If you'd like to help implement any phase, say so — we'll coordinate
Thanks for reading this far. Looking forward to the discussion.
Summary
Webex recently published all their public API specs at webex/webex-openapi-specs — 9 OpenAPI JSON files covering every Webex service family, updated nearly every day via an automated pipeline. We'd like to use those specs to auto-generate a thin network layer inside this SDK so it can never fall behind the Webex API again.
This is an RFC (Request for Comments). We have a full design spec and want community input before writing any code.
The problem today
The SDK's 22 API wrapper files are entirely hand-maintained. When Webex adds or changes a parameter, someone has to notice and manually update the code. In practice, that doesn't always happen quickly — or at all.
Known drift that already exists right now:
events.pyserviceTypeparameter;resourceenum values are stale (docs say "messages, memberships" — spec shows 8+ values)rooms.py/room/linkedFolders) not in SDKAnd the
webex/webex-openapi-specsrepo gets ~daily commits, so this gap only grows.The proposed solution: a three-layer architecture
Rather than replacing the hand-written code, we'd add a generated layer underneath it:
What changes
generator/openapi_to_generated.pyscript reads the Webex OpenAPI JSON files and writeswebexpythonsdk/_generated/*.pyapi/*.pyclasses delegate their HTTP calls into the generated layer instead of callingself._sessiondirectlyWhat stays exactly the same
Every part of the SDK users interact with today is preserved:
@generator_containerreusable paginationcheck_type()messages.create()AdaptiveCardobject handling inmessages.create()**request_parametersescape hatch on every methodmessages.editalias,people.me(),rooms.get_meeting_info(),messages.list_direct()— all keptWhat gets better immediately
**request_parametersto callers right away — no SDK change neededWhat a generated function looks like
And the custom layer on top stays nearly identical to today — it just swaps
self._session.get_items(...)for_gen.list_messages(self._session, ...).Testing approach
The plan includes a strict no-regression testing strategy:
Full design spec
A detailed implementation spec lives on the working branch:
docs/openapi-integration-spec.mdIt covers the full phase-by-phase plan, the generator design, the refactoring order for all 22 API files, the complete test matrix, the CI workflow design, a traceability table mapping every existing behavior to its test, and a rollback plan.
Questions for the community
We want to hear from you before starting implementation:
Does this approach make sense to you? The generated layer is a new internal concept — does it feel like the right separation of concerns, or does it add unwanted complexity?
Are there any existing behaviors we haven't accounted for? If you use the SDK in ways that rely on something subtle in the current implementation, please share — we want to catch it before the refactor, not after.
Which new API families should we prioritize? Cloud Calling, Contact Center, BroadWorks, Device, UCM, Wholesale — all currently have zero SDK coverage. What would be most useful to expose first?
Meetings generator: The meetings family already has a custom YAML-based generator. Should we migrate it to the OpenAPI generator, or keep both pipelines running in parallel?
Generated files in the repo: Should
_generated/*.pybe committed to the repo (easy to read the current state, reviewable diffs in PRs) or always built from specs at install/build time (smaller repo, no stale generated code)? We lean toward committing them for transparency, but want input.Any concerns about the daily sync PR cadence? If Webex is updating specs nearly every day, that's potentially a lot of automated PRs. Should we batch them (e.g., weekly) or only open a PR when the generated Python output actually changes (not just the raw JSON)?
How to contribute
Thanks for reading this far. Looking forward to the discussion.