# APIs

> Django REST Framework APIs with auto-generated OpenAPI schemas, TypeScript clients, and authentication support for building modern web applications.

Pegasus comes with a rich ecosystem of APIs that can used by your app’s front end as well as exposed to third-party developers.

## APIs in Pegasus

[Section titled “APIs in Pegasus”](#apis-in-pegasus)

APIs in Pegasus consist of three pieces:

1. **API endpoints**, created with [Django Rest Framework (DRF)](https://www.django-rest-framework.org/). These are the Django views that serve your APIs.
2. **API schemas**, created with [drf-spectacular](https://drf-spectacular.readthedocs.io/en/latest/). These are automatically created by your APIs, and can be used for API documentation and client generation. They follow the [OpenAPI 3](https://spec.openapis.org/oas/v3.1.0) specification.
3. **API clients**, created by [OpenAPI Generator](https://openapi-generator.tech/). These can be used by developers to interact with your APIs. Pegasus ships with a TypeScript (JavaScript) client that is used in your app’s front end by the parts of the app that interact with the backend APIs (e.g. JavaScript charts, and the React/Vue demos).

This might sound like a lot of moving parts, but, critically, *all the logic lives in the API endpoints themselves*. The schemas are auto-generated by the endpoints, and the clients are auto-generated by the schemas. So you only have to maintain your APIs in a single place, and everything else is kept in sync with tooling.

Using the schemas and clients is optional. You can always interact with a Pegasus API by making the appropriate HTTP requests directly. However, using a client can greatly simplify the code you write and improve the development experience. Front end code in Pegasus that interacts with APIs uses it by default.

Additionally, getting API docs “for free” from the schemas can be a big win if you plan to make your project’s API third-party-developer-facing.

## API Documentation

[Section titled “API Documentation”](#api-documentation)

By default, your Pegasus app ships with two built-in sets of API documentation available at the `/api/schema/swagger-ui/` endpoint (<http://localhost:8000/api/schema/swagger-ui> in development) and `/api/schema/redoc/` endpoint (<http://localhost:8000/api/schema/redoc/> in development).

The API docs will look something like this:

**Swagger API docs:**

![Swagger API Docs](/_astro/swagger-api-docs.CyMzYekt_ZX2A8c.webp)

**Redoc API docs:**

![Redoc API Docs](/_astro/redoc-api-docs.9KICU7qX_Z1EUqMg.webp)

## API Clients

[Section titled “API Clients”](#api-clients)

As part of the [front end](/front-end/overview), Pegasus ships with an API client that can be used to interact with your project’s APIs. **This client is automatically generated from your APIs and should not be modified by hand.**

You can find the source code of the API client(s) in the `api-client` folder in your project’s root directory.

*Note: In releases prior to 2024.3 the API client was in the `assets/javascript/api-client` directory.*

### Using the API client

[Section titled “Using the API client”](#using-the-api-client)

There are several example usages of the API client in the Pegasus codebase. The steps, as seen in the employee app demo, are as follows:

**Initialize the API client**

```javascript
import {Cookies} from "./app";
import {Configuration, PegasusApi} from "./api-client";


const apiConfig = new Configuration({
  basePath: 'https://yourserver.com/',  // or pass this in via {{server_url}} template variable
  headers: {
    'X-CSRFToken': Cookies.get('csrftoken'),
  }
})
const client = new PegasusApi(apiConfig);
```

**Call an API**

```javascript
client.employeesList().then((result) => {
  // do something with the API result here
  console.log('your employees are ', result.results);
});
```

### Client method names

[Section titled “Client method names”](#client-method-names)

The easiest way to find out the methods available in the API client is by looking at the source code in `api-client/apis/<AppName>Api.ts`.

Method names are determined by the `operationId` value for the API in the auto-generated `schema.yaml` file. These identifiers are auto-generated, but can be overridden using DRF Spectacular’s `extend_schema_view` and `extend_schema` helper functions.

This can be done for an entire `ViewSet` as follows:

```python
from drf_spectacular.utils import extend_schema_view, extend_schema
from rest_framework import viewsets


@extend_schema_view(
    create=extend_schema(operation_id='employees_create'),
    list=extend_schema(operation_id='employees_list'),
    retrieve=extend_schema(operation_id='employees_retrieve'),
    update=extend_schema(operation_id='employees_update'),
    partial_update=extend_schema(operation_id='employees_partial_update'),
    destroy=extend_schema(operation_id='employees_destroy'),
)
class EmployeeViewSet(viewsets.ModelViewSet):
    # rest of viewset code here
```

The IDs in the Python code will be converted to camelCase in the JavaScript client.

### Generating the OpenAPI3 schema.yml file

[Section titled “Generating the OpenAPI3 schema.yml file”](#generating-the-openapi3-schemayml-file)

In a new Pegasus installation, the OpenAPI3 `schema.yml` will be available at the `/api/schema/` endpoint (<http://localhost:8000/api/schema/> in dev).

If you plan to use the `schema.yml` file in production, it is more efficient to create it once and serve it as a static file. This can be done by running:

```bash
./manage.py spectacular --file static/api-schema.yml
```

Then you can reference the file by using `{% static /api-schema.yml %}` in a Django template.

### Generating the API client

[Section titled “Generating the API client”](#generating-the-api-client)

Anytime you change your APIs you should create a new API client to keep things in sync. This can be done using the [OpenAPI Generator](https://openapi-generator.tech/) project. The [typescript-fetch](https://openapi-generator.tech/docs/generators/typescript-fetch) client is the one used by Pegasus.

#### Running natively (requires Java)

[Section titled “Running natively (requires Java)”](#running-natively-requires-java)

To generate your API client natively, first install the `openapi-generator-cli` (this library also requires `java`):

```bash
npm install @openapitools/openapi-generator-cli -g
```

Then run it as follows:

```bash
openapi-generator-cli generate -i http://localhost:8000/api/schema/ -g typescript-fetch -o ./api-client/
```

The above assumes your Django server is running at <http://localhost:8000>, but you can replace that value with any URL or file system reference to your `schema.yml` file.

#### Running in docker

[Section titled “Running in docker”](#running-in-docker)

You can also generate your API client with docker to avoid having to install Java by running:

```bash
make build-api-client
```

while your server is running. You should see the files in `api-client` get updated.

#### Rebuilding your front end

[Section titled “Rebuilding your front end”](#rebuilding-your-front-end)

After re-creating the API client, you’ll have to rebuild your front end:

```bash
npm run dev
```

Note that introducing breaking changes to your APIs can also break your API client! If you’re unsure if you introduced breaking changes it is worth testing any functionality that depends on the API client.

## Authentication APIs

[Section titled “Authentication APIs”](#authentication-apis)

*Added in version 2024.3. Changed in 2025.4.1*

If you enable the “Use Authentication APIs” checkbox in your project, Pegasus will generate a set of API endpoints for registering and logging in users. These endpoints can be used to integrate your backend with single page applications (SPAs) and mobile apps.

Under the hood, Pegasus uses [allauth headless](https://docs.allauth.org/en/dev/headless/openapi-specification/) for these endpoints.

This feature uses Django’s session-based authentication by default---which works great for single page apps---though it is possible to add in JWT or another token-based authentication scheme to better support mobile applications.

A complete end-to-end example that uses the API authentication feature in a React SPA can be found in the experimental [standalone front end](/experimental/react-front-end). This example includes React/API-based sign up, login, password reset, two-factor authentication, email confirmation and more.

## API Keys

[Section titled “API Keys”](#api-keys)

Pegasus supports the use of API Keys to access APIs, built on top of the [Django REST Framework API Key](https://florimondmanca.github.io/djangorestframework-api-key/) project.

Pegasus includes the ability to create API keys, associate them with your User objects, and access APIs using the key.

### Creating and managing API keys

[Section titled “Creating and managing API keys”](#creating-and-managing-api-keys)

A simple UI for creating, viewing, and revoking API keys is available to end users from the Profile page.

More advanced/customized management of API keys---including the ability to associate names and expiry dates with keys---is available through the Django admin interface.

Note that when an API key is created it will be displayed *once* and will not be available after that.

For more details on working with API keys see [the library documentation](https://florimondmanca.github.io/djangorestframework-api-key/guide/#creating-and-managing-api-keys).

### API keys and Users

[Section titled “API keys and Users”](#api-keys-and-users)

Pegasus associates API keys with your Django `User` objects. This is a good, practical way to get started with API key scoping. All access granted by the key will the same as the associated `CustomUser` object, which allow you to easily create APIs that work with logged-in users *or* API keys.

The `apps.api.models.UserAPIKey` class is used to associate an API key with a `CustomUser`. You can then enable API keys for any user-specific views, by following the instructions for `APIView`s and `ViewSet`s below.

More complex API key permissions---for example, associating a key with a single API or a single team---can be created by following [these instructions](https://florimondmanca.github.io/djangorestframework-api-key/guide/#api-key-models).

To enable API-key support for an `APIView`, or `ViewSet`, use the `IsAuthenticatedOrHasUserAPIKey` permission class in place of `IsAuthenticated`. This will allow either authenticated users or UserAPIKey users to access the APIs. In either case, the associated user object will be available as `request.user`.

You can see an example `APIView` in the `EmployeeDataAPIView` class that ships with the Pegasus examples, and an example `ViewSet` in the `EmployeeViewSet` code.

### Testing API keys

[Section titled “Testing API keys”](#testing-api-keys)

The easiest way to test API key functionality is to use a tool like [curl](https://curl.se/).

The following command can be used to test a user-based API key with a default Pegasus installation:

```bash
curl http://localhost:8000/pegasus/employees/api/employees/ -H "Authorization: Api-Key <your-api-key>"
```

You should replace `<your-api-key>` with the API key displayed when it is created.

## Troubleshooting

[Section titled “Troubleshooting”](#troubleshooting)

### API client requests are failing

[Section titled “API client requests are failing”](#api-client-requests-are-failing)

When API client requests fail you will get error messages in parts of the application that use the API clients, including the Teams UI (if you are using React), and the React/Vue employee examples.

The most common reason that API client requests fail is a mismatch between the absolute URL configured in the server and the servers *actual* URL. This mismatch be fixed by modifying the Django Site object and settings to match the URL you’re loading the site from, as described in the documentation on [absolute URLs](/configuration/#absolute-urls).

In *development* the most common issues are:

1. Your Django Site is not set up for development. Ensure the site’s domain name is `localhost:8000` in your Django admin, [as described here](/configuration/#absolute-urls).
2. You are loading from a mismatched domain. Be sure you are loading your browser at <http://localhost:8000> and not <http://127.0.0.1:8000>. Or alternatively, if you want to use the 127.0.0.1 address, update the Django site accordingly to use that.