Browse Source

chore(api): Update List Your Organizations docs (#70193)

Updates the OrganizationIndexEndpoint to use the modern API
documentation format instead of the legacy format + updates example with
fields added since the API was first published + add query params not
currently included

Completes
https://www.notion.so/sentry/Update-documentation-on-OrganizationIndexEndpoint-GET-a3ace41e39904326bb6f0aa4d216d6a8?pvs=4

![localhost_3000_api_organizations_list-your-organizations_
(1)](https://github.com/getsentry/sentry/assets/45607721/ff4c911f-e157-41ef-b98c-17ea9d5f3eef)
Isabella Enriquez 10 months ago
parent
commit
dc6b07fdfe

+ 0 - 3
api-docs/openapi.json

@@ -93,9 +93,6 @@
     "/api/0/teams/{organization_id_or_slug}/{team_id_or_slug}/stats/": {
       "$ref": "paths/teams/stats.json"
     },
-    "/api/0/organizations/": {
-      "$ref": "paths/organizations/index.json"
-    },
     "/api/0/organizations/{organization_id_or_slug}/eventids/{event_id}/": {
       "$ref": "paths/organizations/event-id-lookup.json"
     },

+ 0 - 64
api-docs/paths/organizations/index.json

@@ -1,64 +0,0 @@
-{
-  "get": {
-    "tags": ["Organizations"],
-    "description": "Return a list of organizations available to the authenticated session.  This is particularly useful for requests with an user bound context.  For API key based requests this will only return the organization that belongs to the key.",
-    "operationId": "List Your Organizations",
-    "parameters": [
-      {
-        "name": "owner",
-        "in": "query",
-        "description": "Restrict results to organizations in which you are an organization owner.",
-        "schema": {
-          "type": "boolean"
-        }
-      },
-      {
-        "$ref": "../../components/parameters/pagination-cursor.json#/PaginationCursor"
-      }
-    ],
-    "responses": {
-      "200": {
-        "description": "Success",
-        "content": {
-          "application/json": {
-            "schema": {
-              "type": "array",
-              "items": {
-                "$ref": "../../components/schemas/organization.json#/Organization"
-              }
-            },
-            "example": [
-              {
-                "avatar": {
-                  "avatarType": "letter_avatar",
-                  "avatarUuid": null
-                },
-                "dateCreated": "2018-11-06T21:19:55.101Z",
-                "id": "2",
-                "isEarlyAdopter": false,
-                "name": "The Interstellar Jurisdiction",
-                "require2FA": false,
-                "slug": "the-interstellar-jurisdiction",
-                "status": {
-                  "id": "active",
-                  "name": "active"
-                }
-              }
-            ]
-          }
-        }
-      },
-      "401": {
-        "description": "Unauthorized"
-      },
-      "403": {
-        "description": "Forbidden"
-      }
-    },
-    "security": [
-      {
-        "auth_token": ["org: read"]
-      }
-    ]
-  }
-}

+ 29 - 14
src/sentry/api/endpoints/organization_index.py

@@ -1,6 +1,7 @@
 from django.conf import settings
 from django.db import IntegrityError
 from django.db.models import Count, Q, Sum
+from drf_spectacular.utils import extend_schema
 from rest_framework import serializers, status
 from rest_framework.request import Request
 from rest_framework.response import Response
@@ -13,6 +14,11 @@ from sentry.api.bases.organization import OrganizationPermission
 from sentry.api.paginator import DateTimePaginator, OffsetPaginator
 from sentry.api.serializers import serialize
 from sentry.api.serializers.models.organization import BaseOrganizationSerializer
+from sentry.api.serializers.types import OrganizationSerializerResponse
+from sentry.apidocs.constants import RESPONSE_FORBIDDEN, RESPONSE_NOT_FOUND, RESPONSE_UNAUTHORIZED
+from sentry.apidocs.examples.organization_examples import OrganizationExamples
+from sentry.apidocs.parameters import CursorQueryParam, OrganizationParams
+from sentry.apidocs.utils import inline_sentry_response_serializer
 from sentry.auth.superuser import is_active_superuser
 from sentry.db.models.query import in_iexact
 from sentry.models.organization import Organization, OrganizationStatus
@@ -48,28 +54,37 @@ class OrganizationPostSerializer(BaseOrganizationSerializer):
         return value
 
 
+@extend_schema(tags=["Organizations"])
 @region_silo_endpoint
 class OrganizationIndexEndpoint(Endpoint):
     publish_status = {
-        "GET": ApiPublishStatus.UNKNOWN,
-        "POST": ApiPublishStatus.UNKNOWN,
+        "GET": ApiPublishStatus.PUBLIC,
+        "POST": ApiPublishStatus.PRIVATE,
     }
     permission_classes = (OrganizationPermission,)
 
+    @extend_schema(
+        operation_id="List Your Organizations",
+        parameters=[
+            OrganizationParams.OWNER,
+            CursorQueryParam,
+            OrganizationParams.QUERY,
+            OrganizationParams.SORT_BY,
+        ],
+        request=None,
+        responses={
+            200: inline_sentry_response_serializer(
+                "ListOrganizations", list[OrganizationSerializerResponse]
+            ),
+            401: RESPONSE_UNAUTHORIZED,
+            403: RESPONSE_FORBIDDEN,
+            404: RESPONSE_NOT_FOUND,
+        },
+        examples=OrganizationExamples.LIST_ORGANIZATIONS,
+    )
     def get(self, request: Request) -> Response:
         """
-        List your Organizations
-        ```````````````````````
-
-        Return a list of organizations available to the authenticated
-        session.  This is particularly useful for requests with an
-        user bound context.  For API key based requests this will
-        only return the organization that belongs to the key.
-
-        :qparam bool owner: restrict results to organizations in which you are
-                            an organization owner
-
-        :auth: required
+        Return a list of organizations available to the authenticated session. This is particularly useful for requests with a user bound context. For API key-based requests this will only return the organization that belongs to the key.
         """
         owner_only = request.GET.get("owner") in ("1", "true")
 

+ 33 - 0
src/sentry/apidocs/examples/organization_examples.py

@@ -2,6 +2,39 @@ from drf_spectacular.utils import OpenApiExample
 
 
 class OrganizationExamples:
+    LIST_ORGANIZATIONS = [
+        OpenApiExample(
+            "List your organizations",
+            value=[
+                {
+                    "avatar": {"avatarType": "letter_avatar", "avatarUuid": None},
+                    "dateCreated": "2018-11-06T21:19:55.101Z",
+                    "features": [
+                        "session-replay-video",
+                        "onboarding",
+                        "advanced-search",
+                        "monitor-seat-billing",
+                        "issue-platform",
+                    ],
+                    "hasAuthProvider": False,
+                    "id": "2",
+                    "isEarlyAdopter": False,
+                    "links": {
+                        "organizationUrl": "https://the-interstellar-jurisdiction.sentry.io",
+                        "regionUrl": "https://us.sentry.io",
+                    },
+                    "name": "The Interstellar Jurisdiction",
+                    "require2FA": False,
+                    "requireEmailVerification": False,
+                    "slug": "the-interstellar-jurisdiction",
+                    "status": {"id": "active", "name": "active"},
+                }
+            ],
+            status_codes=["200"],
+            response_only=True,
+        )
+    ]
+
     LIST_PROJECTS = [
         OpenApiExample(
             "List an organization's projects",

+ 40 - 2
src/sentry/apidocs/parameters.py

@@ -116,6 +116,44 @@ class OrganizationParams:
 For example the following are valid parameters:
 - `/?project=1234&project=56789`
 - `/?project=-1`
+""",
+    )
+    OWNER = OpenApiParameter(
+        name="owner",
+        location="query",
+        required=False,
+        type=bool,
+        description="""Specify `true` to restrict results to organizations in which you are an owner.""",
+    )
+    QUERY = OpenApiParameter(
+        name="query",
+        location="query",
+        required=False,
+        type=str,
+        description="""Filters results by using [query syntax](/product/sentry-basics/search/).
+
+Valid query fields include:
+- `id`: The organization ID
+- `slug`: The organization slug
+- `status`: The organization's current status (one of `active`, `pending_deletion`, or `deletion_in_progress`)
+- `email` or `member_id`: Filter your organizations by the emails or [organization member IDs](/api/organizations/list-an-organizations-members/) of specific members included
+- `platform`: Filter your organizations to those with at least one project using this platform
+- `query`: Filter your organizations by name, slug, and members that contain this substring
+
+Example: `query=(slug:foo AND status:active) OR (email:[thing-one@example.com,thing-two@example.com] AND query:bar)`
+""",
+    )
+    SORT_BY = OpenApiParameter(
+        name="sortBy",
+        location="query",
+        required=False,
+        type=str,
+        description="""The field to sort results by, in descending order. If not specified the results are sorted by the date they were created.
+
+Valid fields include:
+- `members`: By number of members
+- `projects`: By number of projects
+- `events`: By number of events in the past 24 hours
 """,
     )
 
@@ -156,7 +194,7 @@ class VisibilityParams:
         location="query",
         required=False,
         type=str,
-        description="""The search filter for your query, read more about query syntax [here](https://docs.sentry.io/product/sentry-basics/search/).
+        description="""Filters results by using [query syntax](/product/sentry-basics/search/).
 
 example: `query=(transaction:foo AND release:abc) OR (transaction:[bar,baz] AND release:def)`
 """,
@@ -175,7 +213,7 @@ example: `query=(transaction:foo AND release:abc) OR (transaction:[bar,baz] AND
 - A function which will be in the format of `function_name(parameters,...)`. See possible functions in the [query builder documentation](/product/discover-queries/query-builder/#stacking-functions).
     - when a function is included, Discover will group by any tags or fields
     - example: `field=count_if(transaction.duration,greater,300)`
-- An equation when prefixed with `equation|`. Read more about [equations here](https://docs.sentry.io/product/discover-queries/query-builder/query-equations/).
+- An equation when prefixed with `equation|`. Read more about [equations here](/product/discover-queries/query-builder/query-equations/).
     - example: `field=equation|count_if(transaction.duration,greater,300) / count() * 100`
 """,
     )