Abort() vs new Error()
Reading Recommendation: Overview > RPC
You may wonder, why not use throw new Error() instead of throw Abort()?
// TodoList.telefunc.js
// Environment: server
import { getContext } from 'telefunc'
export async function getTodoList() {
const { user } = getContext()
if (!user) {
// Instead of `throw Abort()`
throw new Error()
}
// ...
}// TodoList.telefunc.ts
// Environment: server
import { getContext } from 'telefunc'
export async function getTodoList() {
const { user } = getContext()
if (!user) {
// Instead of `throw Abort()`
throw new Error()
}
// ...
}By using throw Abort(), we are telling Telefunc that this is an error that is expected to happen (when a third-party makes an invalid or unprivileged telefunction call). Whereas throw new Error() is unexpected: it should never happen and, if it does happen, then it's a bug in our backend code.
For example, throw Abort() doesn't trigger onBug(), see Guides > Error handling > Error tracking.
Rule
The rule for a correct usage is:
- We use
throw Abort()for errors originating from a wrong public usage of a telefunction. - We use
throw new Error()for errors originating from a wrong internal usage of a function.
Example
// auth/getUser.js
// Environment: server
// Note that `auth/getUser.js` is not a `.telefunc.js` file (`getUser()` is
// not a telefunction but a so-called `getContext()` wrapper).
export { getUser }
import { Abort, getContext } from 'telefunc'
function getUser({ permission }) {
if (!permission) {
throw new Error('Wrong getUser() usage: missing permission')
}
// We avoid typos (a typo like `admni` could have dramatic consequences)
if (!['public', 'admin'].includes(permission)) {
throw new Error('Wrong getUser() usage: unknown permission ' + permission)
}
const { user } = getContext()
if (!user) {
throw Abort()
}
if (permission === 'admin') {
if (!user.isAdmin) {
throw Abort()
}
return user
}
if (permission === 'public') {
return user
}
}// auth/getUser.ts
// Environment: server
// Note that `auth/getUser.ts` is not a `.telefunc.ts` file (`getUser()` is
// not a telefunction but a so-called `getContext()` wrapper).
export { getUser }
import { Abort, getContext } from 'telefunc'
function getUser({ permission }: { permission: string }) {
if (!permission) {
throw new Error('Wrong getUser() usage: missing permission')
}
// We avoid typos (a typo like `admni` could have dramatic consequences)
if (!['public', 'admin'].includes(permission)) {
throw new Error('Wrong getUser() usage: unknown permission ' + permission)
}
const { user } = getContext()
if (!user) {
throw Abort()
}
if (permission === 'admin') {
if (!user.isAdmin) {
throw Abort()
}
return user
}
if (permission === 'public') {
return user
}
}Such
getContext()wrapper is a common Telefunc technique explained at Guides > Permissions >getContext()wrapping.
// components/Comment.telefunc.js
// Environment: server
import { getUser } from '../auth/getUser'
export async function onCommentDelete(id) {
// Only admins are allowed to delete a comment
const user = getUser({ permission: 'admin' })
const comment = await Comment.findOne({ id })
await comment.delete()
}// components/Comment.telefunc.ts
// Environment: server
import { getUser } from '../auth/getUser'
export async function onCommentDelete(id: number) {
// Only admins are allowed to delete a comment
const user = getUser({ permission: 'admin' })
const comment = await Comment.findOne({ id })
await comment.delete()
}It is expected that throw Abort() can occur, since onCommentDelete() is a public function anyone can call while not being an admin.
Whereas throw new Error('Wrong getUser() usage') is expected to not occur: if we make a typo and call getUser({ permission: 'admni' }) then it's an internal bug in our backend that we should fix.