# How to instantiate functions in your firewall

import Tabs from '~/components/tabs/Tabs'
import Code from '~/components/Code/Code.astro'


Instantiate [serverless functions](/en/documentation/products/secure/firewall/functions-instances/) directly within your firewall.

This guide uses the configured [Deny a request based on Geoip](/en/documentation/products/applications/functions/javascript-examples/deny-request/) function. You can repeat this process using any function already available on [Azion Marketplace](/en/documentation/products/marketplace/) or [develop other functions](/en/documentation/products/guides/edge-functions/api-builder/).

This guide will also presume you have a network list of the [Countries type](/en/documentation/products/secure/edge-firewall/network-layer-protection/network-lists/#types-of-network-lists).

:::caution[warning]
You must activate the [Functions](/en/documentation/products/secure/firewall/functions/) module to implement functions in your applications. If **Functions** is activated, computing time and invocations could generate usage-related costs. Check the [pricing page](/en/documentation/products/pricing/) for more information.
:::
---

<Tabs client:visible>
    <Fragment slot="tab.console">Console</Fragment>
    <Fragment slot="tab.api">API</Fragment>

<Fragment slot="panel.console">
1. Access [Azion Console](/en/documentation/products/guides/how-to-access-azion-console/) > select **Firewall**.
2. Click the firewall you want to configure.
3. In the **Main Settings** tab, enable the **Functions** module switch to enable functions.
4. Click the **Save** button.
5. Go to the **Functions Instances** tab.
6. Click **+ Function Instance**.
7. Name your function instance. For example: `Deny Geoip function`.
8. On the **Functions** dropdown, select the function you want to use. In this example, `Deny Geoip function`.
 - If you want, you can edit the **Arguments**.
9. Click the **Save** button.

The functions page now lists the newly created instance. However, this new function isn't yet active in your application. You need to define what will trigger the function.

Still on the **Firewall** page:

1. Navigate to the **Rules Engine** tab.
2. Click the **+ Rule** button.
3. Give a name to your rule.
4. Under the **Criteria** section, select the variable `Network`.
5. As a comparison operator, select **matches**.
6. As an argument, select the network list of the Countries type you want to use. For example: `Blocked Countries Geoip`.
7. In the **Behaviors** section, select **Run Function** from the behavior list.
8. Select the function you want to use. In this example, `Deny Geoip function`.
9. Click the **Save** button.

Once your application receives a request generated from one of the countries in the network list, the function in your firewall will deny the request based on the geo IP.
</Fragment>

<Fragment slot="panel.api">
1. Run the following `PATCH` request in your terminal, replacing `[TOKEN VALUE]` with your [personal token](/en/documentation/products/guides/personal-tokens/) and the `<edge_firewall_id>` variable with [your firewall ID](https://api.azion.com/v4#/operations/GetEdgeFirewallFirewalls) to activate the **Functions** module:

<Code lang="bash" code={`
curl --request PATCH \
  --url https://api.azion.com/v4/edge_firewall/firewalls/<edge_firewall_id> \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
    "modules": {
      "edge_functions": { "enabled": true },
    },
  }'
`} />


2. You'll receive a response with the updated value.
3. Run the following `GET` request to retrieve the `edge_function_id` of the `Deny Geoip function` function:

<Code lang="bash" code={`
curl --request GET \
  --url https://api.azion.com/v4/edge_functions/functions \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]]'
`} />

4. You'll receive a response similar to this:

<Code lang="json" code={`
{
  "count": 1,
  "total_pages": 1,
  "schema_version": 3,
  "links": {
    "previous": null,
    "next": null
  },
  "results": [
    {
      "id": 13426,
      "name": "Deny Geoip function",
      "language": "javascript",
      "code": "async function firewallHandler(event){\n    // Access the country code through geoip\n    let countryCode = event.request.metadata[\"geoip_country_code\"]\n\n    // Do some logic here\n    // In this example, we are blocking access from Brazil\n    if (countryCode === \"BR\"){\n        event.deny();\n    }\n\n    // Then, if it comes from any other country,\n    // the processing continues\n    event.continue();\n}\n\naddEventListener(\"firewall\", (event)=>event.waitUntil(firewallHandler(event)));",
      "json_args": {
        "value": "hello_world"
      },
      "function_to_run": "",
      "initiator_type": "edge_firewall",
      "active": true,
      "last_editor": "user@email.com",
      "modified": "2023-11-14T20:09:48.657555Z",
      "is_proprietary_code": false,
      "reference_count": 1
    }
  ]
}
`} />

5. Copy the `<function_id>` value.
6. Run the following `POST` request, replacing the `<edge_firewall_id>` variable with [your firewall ID](https://api.azion.com/#090fa5b0-3d68-4521-9a90-f4d93773f6d9) and the `<function_id>` value with the value you received in the previous response:

<Code lang="bash" code={`
curl --request POST \
  --url https://api.azion.com/v4/edge_firewall/firewalls/<edge_firewall_id>/functions \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Deny Geoip",
  "args": {
  },
  "edge_function": <function_id>,
  "active": true
}'
`} />

7. You'll receive a response similar to this:

<Code lang="json" code={`
{
  "results": {
    "name": "Deny Geoip",
    "json_args": {},
    "edge_function": <function_id>,
    "last_modified": "2023-11-22T18:50:11.812819Z",
    "last_editor": "your-email@example.com",
    "id": 2806
  },
  "schema_version": 3
}
`} />


| Key | Description |
| --- | ----------- |
| `name` | Name of the instantiated function |
| `edge_function` | The ID of the function. This isn't the same as the ID of the instantiated function, which is unique for each application's function instance |
| `json_args` | Definition of arguments required for the function. Some functions don't take arguments |

8. Run the following `GET` to retrieve the `id` of the `Blocked Countries Geoip` network list:

<Code lang="bash" code={`
curl --request GET \
  --url https://api.azion.com/v4/workspace/network_lists \
  --header 'Accept: application/json' \
  --header 'Authorization: Token azion060b7df4369b5688b37b4645a3f5199db87'
`} />

9. You'll receive a response similar to this:

<Code lang="json" code={`
{
  "count": 2,
  "total_pages": 1,
  "schema_version": 3,
  "links": {
    "previous": null,
    "next": null
  },
  "results": [
    {
      "id": 6217,
      "last_editor": "your-email@example.com",
      "last_modified": "2023-11-14T21:35:39.808175Z",
      "list_type": "countries",
      "name": "Deny Geoip",
      "country_list": [
        "Brazil"
      ],
      "ip_list": []
    }
  ]
}
}
`} />

| Key | Description |
| --- | ----------- |
| `name` | Name of the network list |
| `id` | ID of the network list |
| `list_type` | Definition of the type of the network list |
| `country_list` | Items that compose the list |
  
10. Run the following `POST` request in your terminal, replacing `[TOKEN VALUE]` with your [personal token](/en/documentation/products/guides/personal-tokens/), the `<edge_firewall_id>` variable with your firewall ID, the `<edge_function_instance_id>` value with the function instance ID, and the `<<network_list_id>>` value with the network list ID:

<Code lang="bash" code={`
curl --request POST \
  --url https://api.azion.com/v4/edge_firewall/firewalls/{edge_firewall_id}/request_rules \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "Create rule",
    "active": true,
    "criteria": [
      [
        {
          "conditional": "if",
          "variable": "\${network}",
          "operator": "is_in_list",
          "argument": <network_list_id>
        }
      ]
    ],
    "behaviors": [
      {
        "type": "run_function",
        "attributes": {
          "function_instance_id": <edge_function_instance_id>
        }
      }
    ]
  }'
`} />

:::note
For more information on the rules endpoint, see [Work with Rules Engine](/en/documentation/products/guides/secure/work-with-rules-engine/).
:::

11. Wait a few minutes for the changes to propagate.

Once your application receives a request generated from one of the countries in the network list, the function in your firewall will deny the request based on the geo IP.

:::tip
Check the [Azion API documentation](https://api.azion.com/) to know more about what the Azion API can offer.
:::
</Fragment>

</Tabs>

---