Event-based telefunctions

With REST/GraphQL, API endpoints are:

  • Generic.
  • Backend-owned. (It's the backend development/team that creates and defines API endpoints.)

With Telefunc, it's usually the opposite as telefunctions usually are:

  • Tailored.
  • Frontend-owned. (It's the frontend development/team that creates and defines telefunctions.)

This inversion leads to a significantly faster development speed.

You may be tempted to create generic telefunctions out of the habit of using REST/GraphQL, but this is usually an anti-pattern as explained in the example below. Instead, we recommend implementing what we call event-based telefunctions.

Example

Let's imagine a to-do list app that got a new feature request to implement a new button "mark all tasks as completed".

With a RESTful API, the app would typically do these requests:

HTTP VERB       HTTP URL                                      HTTP BODY PAYLOAD
=========       =========================================     =====================
GET             https://api.todo.com/task?completed=false     ∅
POST            https://api.todo.com/task/42                  { "completed": true }
POST            https://api.todo.com/task/1337                { "completed": true }
POST            https://api.todo.com/task/7                   { "completed": true }

With REST, it's usually the backend team that owns and is responsible for implementing and modelling the API.

This is inefficient as the app does N+1 requests, where N is the number of tasks that needs to be updated.

With Telefunc, you can do this instead:

// TodoList.telefunc.ts
// Environment: server
 
export async function onMarkAllAsCompleted() {
  // With SQL
  await sql('UPDATE tasks SET completed = true WHERE completed = false')
 
  // With an ORM
  const updateUser = await Tasks.update({
    where: {
      completed: false
    },
    data: {
      completed: true
    }
  })
}

With Telefunc, it's usually the frontend team that owns and is responsible for defining telefunctions.

The key difference is that the telefunction onMarkAllAsCompleted() is created specifically to serve the needs of the component TodoList.tsx, whereas a RESTful API is a set of generic endpoints that are agnostic to your frontend.

Not only is it more performant, but it's also faster to implement tailored telefunctions. You can implement telefunctions hand-in-hand with your frontend development instead of having to implement an entire RESTful API before even getting started with your frontend development.

Thus, in general, we recommend implementing telefunctions that are tailored instead of generic.

We recommend naming telefunctions onSomeEvent() since they are usually triggered by some kind of event. For example, the telefunction onMarkAllAsCompleted() is triggered by the user clicking on a button:

// TodoList.tsx
// Environment: client
 
import { onMarkAllAsCompleted } from './TodoList.telefunc.ts'
 
function TodoList() {
  return <>
    {/* ... */}
    <button onClick={() => onMarkAllAsCompleted()}>
      Mark all as completed
    </button>
  </>
}

Naming convention

In general, we recommend naming telefunctions onSomeEvent() such as:

    TELEFUNCTION NAME
    =================
  # Generic telefunction:
  updateTodoItem
  # Telefunctions tailored to user events:
  onTodoItemTextUpdate
  onTodoItemCompleteToggle
 
    # Fetching data:
  loadData
  onLoad
  onPagination
  onInfiniteScroll

We also recommend to collocate .telefunc.js files with UI component files:

    FILES
    ===============================
    # UI Component
    components/TodoItem.tsx
    # Telefunction
  components/TodoItem.telefunc.ts
  db/todo.telefunc.ts
 
    # UI Component
    pages/edit/+Page.vue
    # Telefunction
  pages/edit/Page.telefunc.js
  pages/edit/all.telefunc.js

First-time Telefunc users often create generic telefunctions out of the habit of using REST/GraphQL, but defining tailored telefunctions instead is usually the better approach as explained above.

Telefunc displays a warning whenever the naming convention isn't followed. You can remove the warning with config.disableNamingConvention.

Exceptions

While we generally recommend implementing telefunctions that are tailored instead of generic, there are exceptions.

The most common exception is if your telefunctions are consumed by not only one client but several clients that are are developed and deployed independently of each other. In that case it can make sense to define few generic telefunctions covering all clients, instead of defining different telefunctions for each client. Alternatively, you can deploy one Telefunc server per client in order to preserve the fast development speed of tailored telefunctions.