-
Notifications
You must be signed in to change notification settings - Fork 95
feat/externalapi: Add API migration guide #1644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+60
−8
Merged
Changes from 6 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
c7c808a
doc update
julialeex cd4f7ab
Update index.mdx
julialeex f8033d0
Update index.mdx
julialeex eb8c3c3
add image
julialeex a3d72d0
fix
julialeex 62a15a4
Merge branch 'main' into jlxu/api_migration
julialeex 0af6822
address PR comments
julialeex c32d658
move the doc location
julialeex db91b6d
update link
julialeex 7a54074
Merge branch 'main' into jlxu/api_migration
julialeex 3200794
AI-assisted migration
julialeex 7e8a679
fix
julialeex 9fb583d
Merge branch 'main' into jlxu/api_migration
julialeex 19d2f3f
address pr comments
julialeex c12e7ac
Apply suggestion from @bobheadxi
julialeex b7943fb
Recommend generating new access token in migration checklist
julialeex 59896b2
fix
julialeex 765be02
update current user name
julialeex b85da3f
remove the migration checklist
julialeex 8b09b0d
Merge branch 'main' into jlxu/api_migration
julialeex fe5f119
remove more ?preview
julialeex 4da8fd3
fix
julialeex File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,330 @@ | ||
| # Upgrading to the new Sourcegraph API | ||
|
|
||
| Starting in Sourcegraph 7.0, Sourcegraph introduces a new, versioned API at `/api/`. **The new API provides stable, supported endpoints** for functionality previously served by the experimental Deep Search API (`/.api/deepsearch/v1`) and the GraphQL API (`/.api/graphql`). | ||
|
julialeex marked this conversation as resolved.
Outdated
|
||
|
|
||
| Two services are available today: | ||
|
julialeex marked this conversation as resolved.
Outdated
|
||
|
|
||
| - **`deepsearch.v1.Service`** — replaces the experimental `/.api/deepsearch/v1` endpoints (create conversations, poll for results, manage follow-ups) | ||
| - **`users.v1.Service`** — replaces GraphQL user queries and mutations (get, list, update, delete users) | ||
|
|
||
| An interactive API reference is available at `/api-reference` on your Sourcegraph instance (e.g. `https://sourcegraph.example.com/api-reference`), where you can view all operations and download the OpenAPI schema. | ||
|
|
||
|  | ||
|
julialeex marked this conversation as resolved.
Outdated
|
||
|
|
||
| ## What changed | ||
|
|
||
| 1. **Protocol**: REST / GraphQL → [ConnectRPC](https://connectrpc.com/) (always POST with JSON) | ||
|
julialeex marked this conversation as resolved.
Outdated
|
||
| 2. **Base URL**: `/.api/deepsearch/v1/...` and `/.api/graphql` → `/api/{service}/...` | ||
| 3. **Auth header**: `Authorization: token <TOKEN>` → `Authorization: Bearer <TOKEN>` | ||
| 4. **Token scopes**: Any access token → token with `externalapi:read` / `externalapi:write` scope | ||
| 5. **`X-Requested-With` header**: No longer required | ||
| 6. **Resource identifiers**: Numeric IDs (`140`) → resource names (`users/-/conversations/140`) | ||
| 7. **Status field** (Deep Search): `status: "processing"` → `state: "STATE_PROCESSING"` | ||
|
|
||
| ## Why migrate | ||
|
|
||
| - **Stability guarantees** — the new API is versioned with backwards compatibility commitments | ||
| - **Interactive documentation** — explore and test at `/api-reference` | ||
| - **OpenAPI schema** — generate typed clients in any language | ||
| - **Scoped tokens** — finer-grained access control with `externalapi:read` / `externalapi:write` | ||
|
|
||
| ## Endpoint mapping | ||
|
julialeex marked this conversation as resolved.
Outdated
|
||
|
|
||
| ### Deep Search (`/.api/deepsearch/v1` → `deepsearch.v1.Service`) | ||
|
|
||
| | Operation | Old endpoint | New endpoint | | ||
| | ------------------- | ------------------------------------------------------ | ----------------------------------------------------------- | | ||
| | Create conversation | `POST /.api/deepsearch/v1` | `POST /api/deepsearch.v1.Service/CreateConversation` | | ||
| | Get conversation | `GET /.api/deepsearch/v1/{id}` | `POST /api/deepsearch.v1.Service/GetConversation` | | ||
| | List conversations | `GET /.api/deepsearch/v1` | `POST /api/deepsearch.v1.Service/ListConversationSummaries` | | ||
| | Add follow-up | `POST /.api/deepsearch/v1/{id}/questions` | `POST /api/deepsearch.v1.Service/AddConversationQuestion` | | ||
| | Cancel question | `POST /.api/deepsearch/v1/{id}/questions/{qid}/cancel` | `POST /api/deepsearch.v1.Service/CancelConversation` | | ||
| | Delete conversation | `DELETE /.api/deepsearch/v1/{id}` | `POST /api/deepsearch.v1.Service/DeleteConversation` | | ||
|
|
||
| ### User management (`/.api/graphql` → `users.v1.Service`) | ||
|
|
||
| | Operation | GraphQL | New endpoint | | ||
| | -------------- | ------------------------------------------- | ----------------------------------------------- | | ||
| | Get user | `query { user(username: "alice") { ... } }` | `POST /api/users.v1.Service/GetUser` | | ||
| | List users | `query { users { nodes { ... } } }` | `POST /api/users.v1.Service/ListUsers` | | ||
| | Update user | `mutation { updateUser(...) { ... } }` | `POST /api/users.v1.Service/UpdateUser` | | ||
| | Delete users | `mutation { deleteUser(...) { ... } }` | `POST /api/users.v1.Service/BatchDeleteUsers` | | ||
| | Undelete users | _(not available in GraphQL)_ | `POST /api/users.v1.Service/BatchUndeleteUsers` | | ||
|
|
||
| ## Migration by example (Python) | ||
|
|
||
| ### Deep Search: Create a conversation | ||
|
|
||
| **Before:** | ||
|
|
||
| ```python | ||
| import requests | ||
|
|
||
| resp = requests.post( | ||
| "https://sourcegraph.example.com/.api/deepsearch/v1", | ||
| headers={ | ||
| "Authorization": f"token {TOKEN}", | ||
| "X-Requested-With": "my-client 1.0.0", | ||
| }, | ||
| json={"question": "Does the repo have a README?"}, | ||
| ) | ||
| conversation = resp.json() | ||
| conversation_id = conversation["id"] | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```python | ||
| import requests | ||
|
|
||
| resp = requests.post( | ||
| "https://sourcegraph.example.com/api/deepsearch.v1.Service/CreateConversation", | ||
| headers={ | ||
| "Authorization": f"Bearer {TOKEN}", | ||
| "Content-Type": "application/json", | ||
| }, | ||
| json={"question": "Does the repo have a README?"}, | ||
| ) | ||
| conversation = resp.json() | ||
| conversation_name = conversation["name"] # e.g. "users/1/conversations/140" | ||
| ``` | ||
|
|
||
| **With curl:** | ||
|
|
||
| ```bash | ||
| # Before | ||
| curl 'https://sourcegraph.example.com/.api/deepsearch/v1' \ | ||
| -H "Authorization: token $TOKEN" \ | ||
| -H 'X-Requested-With: my-client 1.0.0' \ | ||
| -H 'Content-Type: application/json' \ | ||
| -d '{"question":"Does the repo have a README?"}' | ||
|
|
||
| # After | ||
| curl 'https://sourcegraph.example.com/api/deepsearch.v1.Service/CreateConversation' \ | ||
| -H "Authorization: Bearer $TOKEN" \ | ||
| -H 'Content-Type: application/json' \ | ||
| -d '{"question":"Does the repo have a README?"}' | ||
| ``` | ||
|
|
||
| ### Deep Search: Poll for the result | ||
|
|
||
| The polling workflow is the same — keep calling until the status indicates completion. The only changes are the URL, method, and status field name. | ||
|
|
||
| **Before:** | ||
|
|
||
| ```python | ||
| import time | ||
|
|
||
| while True: | ||
| resp = requests.get( | ||
| f"https://sourcegraph.example.com/.api/deepsearch/v1/{conversation_id}", | ||
| headers={ | ||
| "Authorization": f"token {TOKEN}", | ||
| "X-Requested-With": "my-client 1.0.0", | ||
| }, | ||
| ) | ||
| data = resp.json() | ||
| if data["questions"][0]["status"] == "completed": | ||
| print(data["questions"][0]["answer"]) | ||
| break | ||
| time.sleep(2) | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```python | ||
| import time | ||
|
|
||
| while True: | ||
| resp = requests.post( | ||
| "https://sourcegraph.example.com/api/deepsearch.v1.Service/GetConversation", | ||
| headers={ | ||
| "Authorization": f"Bearer {TOKEN}", | ||
| "Content-Type": "application/json", | ||
| }, | ||
| json={"name": conversation_name}, | ||
| ) | ||
| data = resp.json() | ||
| if data["state"] == "STATE_COMPLETED": | ||
| print(data["questions"][0]["answer"]) | ||
| break | ||
| time.sleep(2) | ||
| ``` | ||
|
|
||
| ### Deep Search: Add a follow-up question | ||
|
|
||
| **Before:** | ||
|
|
||
| ```python | ||
| resp = requests.post( | ||
| f"https://sourcegraph.example.com/.api/deepsearch/v1/{conversation_id}/questions", | ||
| headers={ | ||
| "Authorization": f"token {TOKEN}", | ||
| "X-Requested-With": "my-client 1.0.0", | ||
| }, | ||
| json={ | ||
| "conversation_id": conversation_id, | ||
| "question": "What does the README contain?", | ||
| }, | ||
| ) | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```python | ||
| resp = requests.post( | ||
| "https://sourcegraph.example.com/api/deepsearch.v1.Service/AddConversationQuestion", | ||
| headers={ | ||
| "Authorization": f"Bearer {TOKEN}", | ||
| "Content-Type": "application/json", | ||
| }, | ||
| json={ | ||
| "parent": conversation_name, | ||
| "question": "What does the README contain?", | ||
| }, | ||
| ) | ||
| ``` | ||
|
|
||
| ### User management: Get a user | ||
|
|
||
| **Before (GraphQL):** | ||
|
|
||
| ```python | ||
| import requests | ||
|
|
||
| resp = requests.post( | ||
| "https://sourcegraph.example.com/.api/graphql", | ||
| headers={ | ||
| "Authorization": f"token {TOKEN}", | ||
| }, | ||
| json={ | ||
| "query": 'query { user(username: "alice") { id username displayName } }', | ||
| }, | ||
| ) | ||
| user = resp.json()["data"]["user"] | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```python | ||
| import requests | ||
|
|
||
| resp = requests.post( | ||
| "https://sourcegraph.example.com/api/users.v1.Service/GetUser", | ||
| headers={ | ||
| "Authorization": f"Bearer {TOKEN}", | ||
| "Content-Type": "application/json", | ||
| }, | ||
| json={"name": "users/alice"}, | ||
| ) | ||
| user = resp.json() | ||
| ``` | ||
|
|
||
| **With curl:** | ||
|
|
||
| ```bash | ||
| # Before (GraphQL) | ||
| curl 'https://sourcegraph.example.com/.api/graphql' \ | ||
| -H "Authorization: token $TOKEN" \ | ||
| -H 'Content-Type: application/json' \ | ||
| -d '{"query":"query { user(username: \"alice\") { id username displayName } }"}' | ||
|
|
||
| # After | ||
| curl 'https://sourcegraph.example.com/api/users.v1.Service/GetUser' \ | ||
| -H "Authorization: Bearer $TOKEN" \ | ||
| -H 'Content-Type: application/json' \ | ||
| -d '{"name":"users/alice"}' | ||
| ``` | ||
|
|
||
| ### User management: List users | ||
|
|
||
| **Before (GraphQL):** | ||
|
|
||
| ```python | ||
| resp = requests.post( | ||
| "https://sourcegraph.example.com/.api/graphql", | ||
| headers={ | ||
| "Authorization": f"token {TOKEN}", | ||
| }, | ||
| json={ | ||
| "query": "query { users { nodes { id username displayName } } }", | ||
| }, | ||
| ) | ||
| users = resp.json()["data"]["users"]["nodes"] | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```python | ||
| resp = requests.post( | ||
| "https://sourcegraph.example.com/api/users.v1.Service/ListUsers", | ||
| headers={ | ||
| "Authorization": f"Bearer {TOKEN}", | ||
| "Content-Type": "application/json", | ||
| }, | ||
| json={}, | ||
| ) | ||
| users = resp.json()["users"] | ||
| ``` | ||
|
|
||
| ## Response field mapping | ||
|
|
||
| ### Deep Search | ||
|
|
||
| | Old field | New field | | ||
| | ---------------------- | ----------------------------------- | | ||
| | `id: 140` | `name: "users/1/conversations/140"` | | ||
| | `status: "processing"` | `state: "STATE_PROCESSING"` | | ||
| | `status: "completed"` | `state: "STATE_COMPLETED"` | | ||
| | `questions[].answer` | `questions[].answer` (unchanged) | | ||
| | `read_token` | Not exposed | | ||
| | `share_url` | Not exposed | | ||
|
|
||
| ### User management | ||
|
|
||
| | GraphQL field | New field | | ||
| | ------------------------ | ---------------------- | | ||
| | `id` (opaque GraphQL ID) | `name: "users/alice"` | | ||
| | `username` | `username` (unchanged) | | ||
| | `displayName` | `display_name` | | ||
| | `avatarURL` | `avatar_uri` | | ||
| | `createdAt` | `create_time` | | ||
| | `updatedAt` | `update_time` | | ||
|
|
||
| ## Features not yet in the new API | ||
|
|
||
| The following features from the old API do not have equivalents in the new API yet, but are planned to be supported in future versions: | ||
|
|
||
| - Starring conversations | ||
| - Read token rotation and sharing via tokens | ||
| - Bulk delete of all conversations | ||
| - SSE streaming of question processing progress | ||
| - Code search, repository, git metadata, and Batch Changes operations (currently GraphQL-only) | ||
|
julialeex marked this conversation as resolved.
Outdated
|
||
|
|
||
| If you depend on any of these, please reach out at **support@sourcegraph.com**. | ||
|
|
||
| ## Migration checklist | ||
|
|
||
| - [ ] Generate a new access token with `externalapi:read` / `externalapi:write` scopes | ||
| - [ ] Update `Authorization` header from `token <TOKEN>` to `Bearer <TOKEN>` | ||
|
julialeex marked this conversation as resolved.
Outdated
|
||
| - [ ] Remove the `X-Requested-With` header | ||
| - [ ] Update Deep Search endpoint URLs from `/.api/deepsearch/v1/...` to `/api/deepsearch.v1.Service/...` | ||
| - [ ] Update user management calls from `/.api/graphql` to `/api/users.v1.Service/...` | ||
| - [ ] Change all HTTP methods to `POST` | ||
| - [ ] Update resource identifiers from numeric IDs to resource names (e.g. `users/-/conversations/140`) | ||
| - [ ] Update status checks from `"completed"` to `"STATE_COMPLETED"` (Deep Search) | ||
| - [ ] Test end-to-end | ||
|
|
||
| ## Other Sourcegraph APIs | ||
|
|
||
| The existing Sourcegraph GraphQL API and experimental `/.api/deepsearch/` API remain available, but we recommend migrating to the new API at `/api/` for a stable integration experience. If you need features added to the new Sourcegraph API endpoints for your use cases, please reach out at **support@sourcegraph.com**. | ||
|
|
||
| The following APIs continue to work as before and are **not deprecated at this time**: | ||
|
|
||
| - **[GraphQL debug API](/api/graphql/)** (`/.api/graphql`) — code search, repositories, git metadata, Batch Changes, and all other functionality not yet covered by `/api/`. To reflect the GraphQL API's intended purpose, we have renamed it in our documentation and UI to the **Debug API** (or **Debug console**). New `/api/` equivalents will be introduced over time, and we recommend migrating to them as they become available. | ||
| - **[Stream API](/api/stream-api/)** (`/.api/search/stream`) — streaming search results | ||
| - **[Analytics API](/analytics/api/)** (`analytics.sourcegraph.com`) — usage metrics and reporting | ||
|
|
||
| ## Need help? | ||
|
|
||
| If you have questions about the migration or need features not yet available in the new API, reach out at **support@sourcegraph.com**. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.