Actions
Render functions control the data that is pushed from the server to the client. Anything that is sent from a client to a server is considered an action. Actions are internally implemented as POST requests that are handled in Javascript, but once built on the frontend should be fully transparent to you.
Passthrough
passthrough
Only functions that are explicitly marked as actions will be accessable by the frontend. The @passthrough decorator indicates that this function should be called by the frontend and will return an explicit data payload. It will NOT update the render() state of the frontend.
Decorate functions within your ControllerBase that you want to expose. Each of these functions should specify
a return type. Normal passthrough endpoints can return with either a None
, a BaseModel
object, or a
JSONResponse
if you need full flexibility on return headers and content structure.
If you do return a JSONResponse note that we will handle the merging of the response for you - so
on the client side you will still access your endpoint contents as response.passthrough
.
Parameters
- Name
args
- Type
- Description
Default: ()
- Name
kwargs
- Type
- Description
Default: {}
- Name
exception_models
- Type
- list[Type[APIException]] | None
- Description
List of APIException subclasses that this function is known to throw. These will be parsed and available to frontend clients.
- Name
raw_response
- Type
- bool
- Description
If specified, you can return a generic fastapi.Response object. There's no constraint this endpoint returns JSON - you can return html or a custom protocol. This lets you treat this API as a generic POST endpoint for you to fully control the output.
Code
const response = await serverState.my_action({ name: "John Appleseed", }); console.log(response.passthrough.name);
Code
from pydantic import BaseModel class ResponseModel(BaseModel): name: str class MyController(ControllerBase): @passthrough async def my_action(self, name: str) -> ResponseModel: return ResponseModel(name=name)
Sideeffect
sideeffect
Mark a function as causing a sideeffect to the data. This will force a reload of the full (or partial) server state and sync these changes down to the client page.
Like passthroughs, @sideeffect accepts return values of None, BaseModel, or a JSONResponse if you need full flexibility on return headers and content structure. Unlike @passthrough, it does not allow you to provide a non-JSON response since we need to internally merge it with render() sideeffect update.
Parameters
- Name
args
- Type
- Description
Default: ()
- Name
kwargs
- Type
- Description
Default: {}
- Name
exception_models
- Type
- list[Type[APIException]] | None
- Description
List of APIException subclasses that this function is known to throw. These will be parsed and available to frontend clients.
- Name
reload
- Type
- tuple[FieldClassDefinition, ...] | None
- Description
If provided, will ONLY reload these fields on the client side. By default will reload all fields. Otherwise, why specify a sideeffect at all? Note that even if this is provided, we will still regenerate a fully full state on the server as if render() is called again. This parameter only controls the data that is streamed back to the client in order to help reduce bandwidth of data that won't be changed.
- Name
experimental_render_reload
- Type
- bool
- Description
Experimental options. Disabled by default. If True, will attempt to only execute the logic in render() that is required to calculate your
reload
parameters. Other logic will be short-circuited. If your render function has significant computation for other properties this can be a significant performance improvement. However, it is experimental and may not work in all cases.
Code
from mountaineer import sideeffect, RenderBase, ControllerBase, Depends from iceaxe import DBConnection, select from iceaxe.mountaineer import DatabaseDependencies from myapp import models class ControllerRender(RenderBase): count: str class MyController(ControllerBase): async def render( self, db_connection: DBConnection = Depends(DatabaseDependencies.get_db_connection), ) -> ControllerRender: elements = await db_connection.exec(select(models.MyModel.id)) return ControllerRender(count=len(elements)) @sideeffect async def increment_count( self, db_connection: DBConnection = Depends(DatabaseDependencies.get_db_connection), ) -> None: new_model = models.MyModel() await db_connection.insert([new_model])