Designing a New API

Django REST framework(DRF) is a powerful and flexible toolkit for building Web APIs. Sentry APIs are built using DRF. Here are some considerations to make when designing APIs at Sentry.

URL Patterns

The API's URL is what developers use to call the endpoint so it’s important that it is meaningful and clear.

Don't Exceed 3-level Nesting

Nested resources format like api/0/organizations/{org}/projects/ is recommended over api/0/projects/ for readability because it gives user an understanding of resource hierarchy. However, nesting can make URLs too long and hard to use. Sentry uses 3-level nesting as a hybrid solution.

Here are some possible urls for values with this resource hierarchy: organization -> project -> tag -> value

  • πŸ‘ /projects/{organization_slug}/{project_slug}/tags/{tag_id}/values
  • πŸ‘Ž /organizations/{organization_slug}/projects/{project_slug}/tags/{tag_id}/values/
  • πŸ‘Ž /values/

In the above example we flattened projects. The table below shows the existing flattened collections which works out with our existing APIs.

First collection in URLWhen to useParentIdentifierExample
organizationsWhen the resource cannot be attached to any other collection below parent like ProjectN/A - always comes as first collection{organization_slug}Create a New Team
teamsWhen the resource is under a specific team in the hierarchyorganizations{organization_slug}/ {team_slug}Retreive Team Stats
projectsWhen the resource is under a specific project in the hierarchy but not under an issueorganizations{organization_slug}/ {project_slug}Create a New Client Key
issuesWhen the resource is under a specific issue in the hierarchyprojects{issue_id}List an Issue's Events
sentry-app-installationsWhen the resource is mapped to a specific integrationorganizations{integration_slug}Delete an External Issue

Here are some additional examples:

  • πŸ‘ /organizations/{organization_slug}/projects/
  • πŸ‘ /projects/{organization_slug}/{project_slug}/issues/
  • πŸ‘Ž /projects/

Naming Guidance

  • Collection names should be lowercase and hyphenated, e.g. commit-files.
  • Collection names must be plural. Avoid using uncountable words because the user can’t know whether the GET returns one item or a list.
  • Query params and body params should be camelBacked. eg. userId or dateCreated.
  • For sorting and filtering, stick with the common param names: sortBy (e.g. sortBy=-dateCreated), orderBy (either asc or desc), groupBy, limit
  • Path params should be snake_case

Functionality

Each API should be stateless, have a clear purpose, and do one specific thing. To achieve that, stick with the standard methods listed below. If your API needs to be more complicated, work with owners-api on how to create it.

  • πŸ‘ An API that updates project settings: PATCH for updating a field or PUT for updating settings
  • πŸ‘Ž An API that creates a project, creates a team, and creates alerts for that team about that project
FunctionalityHTTP MethodResponse ObjectExample
CreatePOSTSerialized created resourceCreate a Project
UpdatePUT or PATCHSerialized updated resourceUpdate Project Settings
GetGETSerialized single resourceRetrieve a Project
DeleteDELETENoneDelete a Project
ListGETList of multiple serialized resourcesList All the Projects in an Organization
Batch GetGETList of serialized resourcesGet project details for specific project ids
Batch CreatePOSTList of serialized created resourcesCreate multiple projects with the same settings
Batch UpdatePUTList of serialized updated resourcesUpdate a list of issues
Batch DeleteDELETENoneDelete a list of issues

Here are some examples of how to use standard methods to represent complex tasks:

  • Get count of a resource
    • Count is part of the List API and is provided in header X-Total-Count param
  • Get latest of a resource
    • Order and filtering should happen as part of list api query parameters. Here’s a good read.
    • πŸ‘Ž /api/0/issues/{issue_id}/events/latest/
    • πŸ‘ /api/0/issues/{issue_id}/events?orderBy=-date,limit=1, - for descending

Batch vs. Single Resource Methods

Here are some notes that can help you decide between similar methods. We use Get here as an example but the same applies to all the other methods in the parenthesis.

  • Get (Update, Delete): Use get on the {resource}DetailsEndpoint to retrieve a resource. For example, ProjectDetailsEndpoint.
  • List (Create, Batch Create, Batch Update, Batch Delete): Use get on the {resource-parent}{resource}Endpoint to retreive all resources that belong to that parent. For example TeamProjectsEndpoint.
  • Batch Get (Batch Create, Batch Update, Batch Delete): Use get on the {root-parent}{resource}Endpoint. The difference between Batch and List is that batch usually includes a list of ids as query parameter and returns details about those ids. This list does not necessarily belong to one parent. For example, we can't retrieve two projects that belong to two different teams in the above example and in that case we use the get method in the root resource, in this case OrganizationProjectsEndpoint.

Response Object

Each response object returned from an API should be a serialized version of the Django model associated with the resource. You can see all the existing serializers here.

You can edit this page on GitHub.