---
id: validation-action
sidebar_label: Slot Validation Actions
title: Slot Validation Actions
abstract: Learn how `ValidationAction` class is implemented in the Rasa SDK.
---

There are two helper classes in Rasa SDK with the role of executing custom slot extraction and validation:
- `ValidationAction`: the base class for custom actions extracting and validating slots that can be set or updated
outside of a form context.
- `FormValidationAction`: the base class for custom actions extracting and validating slots that are set only within
the context of a form.

In order to implement custom slot extraction and validation logic, you have the option of subclassing either
`ValidationAction` or `FormValidationAction` class, depending on the context in which you want to set or update slots.

## `ValidationAction` class

You can extend the `ValidationAction` class in the Rasa SDK to define custom extraction and / or validation of slots that
can be set or updated outside of a form context.

:::note
`ValidationAction` is intended for extracting slots **outside** the context of a form.
It will ignore extraction and validation methods for any slots that have a form specified under the
[slot mapping's `conditions`](../domain.mdx#mapping-conditions).
It will not run these methods when the specified form is active nor when no form is active.
Please extend the [`FormValidationAction`](./validation-action.mdx#formvalidationaction-class) class to apply
custom slot mappings only within the context of a form.
:::

### How to subclass `ValidationAction`

Firstly, you must add the name of this action, `action_validate_slot_mappings`, to the domain `actions` list.
Note that you do not need to implement the `name` method in the custom action extending `ValidationAction`, since this
is already implemented. If you override the `name` method, the custom validation action will not run because the
original name is hardcoded in the call that the default action `action_extract_slots` makes to the action server.

You should create only one subclass of `ValidationAction` which should contain all extraction and validation
methods for different slots according to your use-case.

With this option, you do not need to specify the `action` key in the [custom slot mapping](../domain.mdx#custom-slot-mappings),
since the default action [`action_extract_slots`](../default-actions.mdx#action_extract_slots) runs `action_validate_slot_mappings`
automatically if present in the `actions` section of the domain.

#### Validation of Slots with Predefined Mappings

To validate slots with a predefined mapping, you must write functions named `validate_<slot_name>`.

In the following example, the value for slot `location` is capitalized only if the extracted value is of type string:

```python
from typing import Text, Any, Dict

from rasa_sdk import Tracker, ValidationAction
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.types import DomainDict


class ValidatePredefinedSlots(ValidationAction):
    def validate_location(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        """Validate location value."""
        if isinstance(slot_value, str):
            # validation succeeded, capitalize the value of the "location" slot
            return {"location": slot_value.capitalize()}
        else:
            # validation failed, set this slot to None
            return {"location": None}
```

#### Extraction of Custom Slot Mappings

To define custom extraction code, write an `extract_<slot_name>` method for every slot with a
custom slot mapping.

The following example shows the implementation of a custom action that extracts the slot `count_of_insults` to keep
track of the user's attitude.

```python
from typing import Dict, Text, Any

from rasa_sdk import Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.forms import ValidationAction


class ValidateCustomSlotMappings(ValidationAction):
    async def extract_count_of_insults(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> Dict[Text, Any]:
        intent_of_last_user_message = tracker.get_intent_of_latest_message()
        current_count_of_insults = tracker.get_slot("count_of_insults")
        if intent_of_last_user_message == "insult":
           current_count_of_insults += 1

        return {"count_of_insults": current_count_of_insults}
```

### `ValidationAction` class implementation

`ValidationAction` is a subclass of the `Action` Rasa SDK class and the abstract Python `ABC` class.
Therefore the class implements the `name` and `run` methods inherited from `Action`.
In addition, `ValidationAction` implements more specialized methods that will be called in the `run` method:
- `get_extraction_events`: Extracts custom slots using available `extract_<slot name>` methods
- `get_validation_events`: Validates slots by calling available `validate_<slot name>` methods for each slot
- `required_slots`: Returns slots which the validation action should fill

#### Methods

##### ValidationAction.name

Defines the action's name: this must be hardcoded as `action_validate_slot_mappings`.

* **Returns**:

  Name of action

* **Return type**:

  `str`

##### ValidationAction.run

```python
async ValidationAction.run(dispatcher, tracker, domain)
```

The `run` method executes the custom extraction code defined in `extract_<slot name>` methods by calling the
`get_extraction_events` method, then updates the tracker with the returned events.
The `run` method will also execute custom validation code defined in `validate_<slot name>` methods via the
`get_validation_events` method and add the returned events to the tracker.

###### **Parameters**

  * **dispatcher** – the dispatcher which is used to
    send messages back to the user. Use
    `dispatcher.utter_message()` or any other
    `rasa_sdk.executor.CollectingDispatcher`
    method. See the [documentation for the dispatcher](./sdk-dispatcher.mdx)

  * **tracker** – the state tracker for the current
    user. You can access slot values using
    `tracker.get_slot(slot_name)`, the most recent user message
    is `tracker.latest_message.text` and any other
    `rasa_sdk.Tracker` property. See the [documentation for the tracker](./sdk-tracker.mdx).

  * **domain** – the bot's domain

###### **Returns**

  A list of `rasa_sdk.events.Event` instances. See the [documentation for events](./sdk-events.mdx).

###### **Return type**

  `List`[`Dict`[`str`, `Any`]]

##### ValidationAction.required_slots

```python
async ValidationAction.required_slots(domain_slots, dispatcher, tracker, domain)
```

The `required_slots` method will return the `domain_slots` which is a list of all slot names mapped in the domain that
do not include any slot mapping with conditions. `domain_slots` is returned by the `domain_slots` method, which only takes
`Domain` as an argument.

###### **Returns**

  A list of slot names of type `Text`.

##### ValidationAction.get_extraction_events

```python
async ValidationAction.get_extraction_events(dispatcher, tracker, domain)
```

The `get_extraction_events` method will gather the list of slot names via `required_slots` method call and then loop
through every slot name to run the `extract_<slot name>` method if available.

##### **Returns**

  A list of `rasa_sdk.events.SlotSet` instances. See the [documentation for SlotSet events](./sdk-events.mdx#slotset).

##### ValidationAction.get_validation_events

```python
async ValidationAction.get_validation_events(dispatcher, tracker, domain)
```

The `get_validation_events` method will gather the list of slot names to validate via `required_slots` method call.
Then it will get a mapping of slots which were recently set and their values via `tracker.slots_to_validate` call.
Looping through this mapping of recently extracted slots, it will check if the slot is in `required_slots` then run the
`validate_<slot name>` method if available for that slot.

###### **Returns**

  A list of `rasa_sdk.events.SlotSet` instances. See the [documentation for SlotSet events](./sdk-events.mdx#slotset).

## `FormValidationAction` class

A `FormValidationAction` custom action will only run if the form it specifies in its name is activated.
If certain custom slot mappings should only be extracted and / or validated within the context of a form,
the custom action should inherit from `FormValidationAction` rather than from `ValidationAction`.

Since a custom action extending `FormValidationAction` runs on every user turn only as long as the form is active, it is
not required to use mapping conditions in this case.

To learn more about how to implement this class, see Forms [Advanced Usage](../forms.mdx#advanced-usage).

### `FormValidationAction` class implementation

`FormValidationAction` is a subclass of the `ValidationAction` Rasa SDK class and the abstract Python `ABC` class.
`FormValidationAction` inherits most methods from `ValidationAction` class, however it overrides the `name` and
`domain_slots` methods, implements a new method `next_requested_slot` and extends the implementation of `run` method.

#### Methods

##### FormValidationAction.name

The method `name` will raise a `NotImplementedError` exception if the bot custom action subclassing `FormValidationAction`
does not return a custom name which follows this naming convention: `validate_<form name>`.

##### FormValidationAction.required_slots

The method `required_slots` will return the `domain_slots` which is a list of all slot names included in the form's
`required_slots`. `domain_slots` is returned by the `domain_slots` method, which only takes
`Domain` as an argument.

##### FormValidationAction.next_requested_slot

The method `next_requested_slot` will set the value of `REQUESTED_SLOT` to the next unset slot only if the
`required_slots` method was overridden by the custom action subclassing `FormValidationAction`.

If users didn't override `required_slots` then we'll let the `FormAction` within Rasa Open
Source request the next slot, and the method will return `None`.

The parameters the method requires are:
- [dispatcher](./sdk-dispatcher.mdx)
- [tracker](./sdk-tracker.mdx)
- the bot's domain

##### FormValidationAction.run

The original implementation of the `ValidationAction.run` method is extended to add a call to the `next_requested_slot`
method. The output of the `next_requested_slot` method call (if not `None`) is added to the list of events that `run`
method returns.
