> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mage.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# API resources

> This file handles the CRUD operations.

When you create a new API called `Swords`, the resource
name is `Sword` and the file name is `SwordResource`. The endpoint for CRUD operations are:

| Action | HTTP method | Endpoint      |
| ------ | ----------- | ------------- |
| Create | `POST`      | `/swords`     |
| List   | `GET`       | `/swords`     |
| Detail | `GET`       | `/swords/:id` |
| Update | `PUT`       | `/swords/:id` |
| Delete | `DELETE`    | `/swords/:id` |

If your resource belongs to a parent model, for example a sword belongs to a team, then your
endpoints will be the following (note that swords for the create and list endpoints are nested
under the `teams` resource:

| Action | HTTP method | Endpoint            |
| ------ | ----------- | ------------------- |
| Create | `POST`      | `/teams/:id/swords` |
| List   | `GET`       | `/teams/:id/swords` |
| Detail | `GET`       | `/swords/:id`       |
| Update | `PUT`       | `/swords/:id`       |
| Delete | `DELETE`    | `/swords/:id`       |

## Collection

This method is executed when you make a request for a list of a specific resource.

Example: `GET /swords`.

Create a file called `SwordResource` that is a subclass of 1 of the following:

1. `GenericResource`: subclass this class if you want to execute arbitrary code
2. `DatabaseResource`: subclass this class only if your resource is directly associated to a
   database model. This subclass has many methods defined by default that handles CRUD operations
   automatically.

### Creating a subclass of `GenericResource`

Create a file called `backend/api/resources/SwordResource.py`:

```python theme={"system"}
from .GenericResource import GenericResource
import requests

class SwordResource(GenericResource):
    @classmethod
    def collection(self, query, meta, user, **kwargs):
        """
        query:
            a dictionary of URL query parameters

        meta:
            a dictionary of meta parameters from the URL; such as _limit and _format

        user:
            a user object that represents the current user who is making the API call

        kwargs:
            a dictionary of other values that are passed down through the API request lifecycle; such
            as parent_model, etc.
        """

        # Fetch a list of Swords from the internet
        response = requests.get('https://www.dropbox.com/s/mnjsxzdsyc39hr3/IkeaStorageJson.json')

        return self.build_result_set(response['swords'], user, **kwargs)
```

### Creating a subclass of `DatabaseResource`

```python theme={"system"}
from .DatabaseResource import DatabaseResource
from examples.models import Sword

class SwordResource(DatabaseResource):
    # Set this class variable to the model that the resource is associated with
    model_class = Sword

    """
    Optionally override collection because the DatabaseResource will handle limits
    and pagination automatically. If you don’t override the collection method, DatabaseResource
    will automatically fetch a list of models from the database for you.
    """
    @classmethod
    def collection(self, query, meta, user, **kwargs):
        """
        Use collection to handle pre-filtering of the results from the database.
        """

        # Filter swords that are weak and belong to the current team
        team = kwargs['parent_model']
        return Sword.objects.filter(team_id=team.id, weak=False)
```

Here is how we would get a list of swords that are weak and belong to team ID 1:

```python theme={"system"}
user = User.objects.get(id=3)
team = Team.objects.get(id=1)

# You typically don’t have to call this function by itself.
# This function is called by making a request to /teams/1/swords.
swords = SwordResource.collection({}, {}, user, parent_model=team)
```

## Create

This method is executed when you make a request to create a new instance of a resource.

Example: `POST /swords`.

### `GenericResource`

```python theme={"system"}
from services.datadog import increment

class SwordResource(GenericResource):
    # code from before

    @classmethod
    def create(self, payload, user, **kwargs):
        """
        payload:
            a dictionary of the request body

            For example, if your request body is { "sword" : { "weak": false } },
            then your payload will be the following dictionary: { 'weak': False }.

            NOTE:
            Payloads must be nested inside a key named after the singular form of the resource name.

        user:
            a user object that represents the current user who is making the API call

        kwargs:
            a dictionary of other values that are passed down through the API request lifecycle;
            such as parent_model, etc.
        """

        # Increment a create metric in DataDog
        increment('swords.create')

        if payload.get('weak'):
            name = 'Weak sword'
        else:
            name = 'Strong sword'

        # Always return a new instance of the resource
        return self({ 'name': name }, user, **kwargs)
```

### `DatabaseResource`

You typically never have to override the `create` class method. The instances where it is overridden
include a scenario when you want to execute a callback function only if the resource was
successfully created.

The `DatabaseResource` `create` method will take the keys and values in the payload argument, assign
those values to a newly instantiated `Sword` object, and then save the model to the database.

```python theme={"system"}
class SwordResource(DatabaseResource):
    # code from before

    @classmethod
    def create(self, payload, user, **kwargs):
        def _upload(resource):
            # upload something only if the resource was successfully created

        self.on_create_callback = _upload

        return super().create(payload, user, **kwargs)
```

## Member

This method is executed when you make a fetch a single resource using it’s ID.
Example: `GET /swords/:id`.

### `GenericResource`

```python theme={"system"}
class SwordResource(GenericResource):
    # code from before

    @classmethod
    def member(self, pk, user, **kwargs):
        """
        pk:
            a string or integer from the URL parameter :id

        user:
            a user object that represents the current user who is making the API call

        kwargs:
            a dictionary of other values that are passed down through the API request lifecycle; such
            as parent_model, etc.
        """

        # Fetch 1 of Sword from the internet
        array = requests.get('https://www.dropbox.com/s/mnjsxzdsyc39hr3/IkeaStorageJson.json')
        sword = filter(lambda x: x['id'] == pk, array)

        return self({ 'name': sword['name'], 'weak': False }, user, **kwargs)
```

### `DatabaseResource`

You almost never have to override the `member` method.
If you do, see `TrainingRunResource` for an example.

## Update

This method is executed when you want to update a single resource using it’s ID.
Example: `PUT /swords/:id`.

This is almost the same as the `create` method except it’s an instance method and the ID of the
resource you want to update must be included in the URL.

```python theme={"system"}
class SwordResource(GenericResource):
    # code from before

    def update(self, payload, **kwargs):
        """
        payload:
            a dictionary of the request body

            For example, if your request body is { "sword" : { "weak": false } },
            then your payload will be the following dictionary: { 'weak': False }.

            NOTE:
            Payloads must be nested inside a key named after the singular form of the resource name.

        kwargs:
            a dictionary of other values that are passed down through the API request lifecycle; such
            as parent_model, etc.
        """

        print('Awesome update!')

        # Always return self
        return self
```

### `DatabaseResource`

You almost never have to override the `update` method.
If you do, see `ModelVersionResource` for an example.

## Delete

This method is executed when you want to delete a single resource using it’s ID.
Example: `DELETE /swords/:id`.

```python theme={"system"}
class SwordResource(GenericResource):
    # code from before

    def delete(self, **kwargs):
        """
        kwargs:
            a dictionary of other values that are passed down through the API request lifecycle; such
            as parent_model, etc.
        """

        print('Deleted!')
```

### `DatabaseResource`

You almost never have to override the `delete` method.

## Registering parent models

If your resource belongs to a parent model, for example a sword belongs to a team, you must do
the following in order for these endpoints to work properly:

1. Create: `POST /teams/:id/swords`
2. List: `GET /teams/:id/swords`

```python theme={"system"}
import importlib

class SwordResource(DatabaseResource):
    # code from before

SwordResource.register_parent_resource(
    getattr(importlib.import_module('api.resources.TeamResource'), 'TeamResource'),
)
```

## Pre-load single associated object

The sword model belongs to a user via the `sword.user_id` column. If you are fetching a list of 100
swords and in your code you are accessing the methods of the `user` object via `sword.user`
(e.g. `sword.user.name`), you will inadvertently make 100 extra API calls to the `users`
database table. Do the following to prevent this:

```python theme={"system"}
import importlib

class SwordResource(DatabaseResource):
    # code from before

SwordResource.register_collective_loader_find(
    getattr(importlib.import_module('api.resources.UserResource'), 'UserResource'),
)
```

## Pre-load multiple associated objects

The sword has many opponents that were defeated by it. You can query all the opponents via the
`swords.opponents.objects.all()` method. This will fetch all opponents from the database where
`opponent.sword_id` equals `sword.id`. If you are accessing the opponents of each sword when
fetching a list of 100 swords, you will be making 100 extra API calls to the `opponents` database.
Do the following to prevent this:

```python theme={"system"}
import importlib

class SwordResource(DatabaseResource):
    # code from before

SwordResource.register_collective_loader_select(
    getattr(importlib.import_module('api.resources.OpponentResource'), 'OpponentResource'),
)
```
