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

# atoti.Session.endpoint()

#### Session.endpoint(route, \*, method='GET')

Create a custom endpoint at `f"/proxy/{route}"`.

<Note>
  Calling this method overrides [`atoti.Session.proxy`](./atoti.Session.proxy#atoti.Session.proxy)’s [`url`](./atoti.proxy.Proxy.url#atoti.proxy.Proxy.url).
</Note>

The endpoint logic is written in Python but the endpoint is exposed by Atoti Server.
This allows to deploy the project in a container or a VM with a single opened port (the one of Atoti Server) instead of two.

The decorated function must:

* take three parameters with respective types:
  * [`atoti.endpoint.Request`](./atoti.endpoint.request#atoti.endpoint.Request)
  * [`atoti.User`](./atoti.user#atoti.User)
  * [`atoti.Session`](./atoti.session#atoti.Session)

* return a response body as JSON convertible data

* **Parameters:**
  * **route** ([*str*](https://docs.python.org/3/library/stdtypes.html#str)) – The template of the path after `"/proxy"`.
    For instance, if `"foo/bar"` is passed, a request to `"/proxy/foo/bar?query=string"` will match.
    Path parameters can be configured by wrapping their name in curly braces in the template.
  * **method** ([*Literal*](https://docs.python.org/3/library/typing.html#typing.Literal) *\[* *'DELETE'* *,*  *'GET'* *,*  *'PATCH'* *,*  *'POST'* *,*  *'PUT'* *]*) – The HTTP method the request must be using to trigger this endpoint.
    `DELETE`, `PATCH`, `POST`, and `PUT` requests can have a body but it must be JSON.

* **Return type:**
  [*Callable*](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)\[\[[*Callable*](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)\[\[[*Request*](./atoti.endpoint.request#atoti.endpoint.Request), [*User*](./atoti.user#atoti.User), [*Session*](./atoti.session#atoti.Session)], JsonValue]], [*Callable*](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)\[\[[*Request*](./atoti.endpoint.request#atoti.endpoint.Request), [*User*](./atoti.user#atoti.User), [*Session*](./atoti.session#atoti.Session)], JsonValue]]

### Example

```pycon theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
>>> df = pd.DataFrame(
...     columns=["Year", "Month", "Day", "Quantity"],
...     data=[
...         (2019, 7, 1, 15),
...         (2019, 7, 2, 20),
...     ],
... )
>>> table = session.read_pandas(
...     df, keys={"Year", "Month", "Day"}, table_name="Quantity"
... )
```

```pycon theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
>>> @session.endpoint("tables/{table_name}/count", method="GET")
... def get_table_row_count(request, user, session, /):
...     table_name = request.path_parameters["table_name"]
...     table = session.tables[table_name]
...     return table.row_count
>>> response = session.client.http_client.get(
...     f"proxy/tables/{table.name}/count"
... )
>>> response.raise_for_status().json()
2
```

```pycon theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
>>> @session.endpoint("tables/{table_name}/rows", method="POST")
... def append_rows_to_table(request, user, session, /):
...     rows = request.body
...     table_name = request.path_parameters["table_name"]
...     table = session.tables[table_name]
...     dataframe = pd.DataFrame(rows, columns=list(table))
...     table.load(dataframe)
>>> response = session.client.http_client.post(
...     f"proxy/tables/{table.name}/rows",
...     json=[
...         (2021, 5, 19, 50),
...         (2021, 5, 20, 6),
...     ],
... )
>>> response.status_code
200
>>> response = session.client.http_client.get(
...     f"proxy/tables/{table.name}/count"
... )
>>> response.raise_for_status().json()
4
>>> table.head()
                Quantity
Year Month Day
2019 7     1          15
           2          20
2021 5     19         50
           20          6
```

The full flow is:

```pycon theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
>>> with TRACER.start_as_current_span("query endpoint") as span:
...     response = session.client.http_client.get(
...         f"proxy/tables/{table.name}/count"
...     )
...     _ = response.raise_for_status()
>>> _print(span)
⏺ query endpoint                                         [atoti.python_sdk]
└── GET /proxy/**                                        [atoti.server]
    └── unsecured request                                [atoti.server]
        └── GET                                          [atoti.server]
            └── GET /tables/{table_name}/count           [atoti.python_sdk]
                ├── Validate authorization               [atoti.python_sdk]
                │   └── POST /graphql                    [atoti.server]
                │       └── unsecured request            [atoti.server]
                │           └── query                    [atoti.server]
                │               └── currentUser          [atoti.server]
                │                   ├── name             [atoti.server]
                │                   └── roles            [atoti.server]
                └── Execute user callback                [atoti.python_sdk]
                    ├── Tables._get_unambiguous_keys     [atoti.python_sdk]
                    │   └── POST /graphql                [atoti.server]
                    │       └── unsecured request        [atoti.server]
                    │           └── query                [atoti.server]
                    │               └── dataModel        [atoti.server]
                    │                   └── database     [atoti.server]
                    │                       └── table    [atoti.server]
                    │                           └── name [atoti.server]
                    └── Table.row_count                  [atoti.python_sdk]
```

<Callout icon="link">
  **See also**:
  [`atoti.Session.proxy`](./atoti.Session.proxy#atoti.Session.proxy).
</Callout>
