Client and server in depth · Lesson 2/4 · 8 min

Callbacks in depth and error handling

Callbacks return data from the server. Learn to pass several arguments and to never leave the client hanging.

You already saw callbacks in the frameworks module. Here we go a step further: multiple arguments, validation and always responding (a callback that never calls cb() leaves the client waiting forever).

lua
-- Server: returns whether they can buy AND how much they have left
ESX.RegisterServerCallback('garaje:sacarCoche', function(source, cb, plate)
  local xPlayer = ESX.GetPlayerFromId(source)
  if not xPlayer then return cb(false, 0) end -- ALWAYS respond

  local coche = MySQL.single.await('SELECT * FROM owned_vehicles WHERE plate = ? AND owner = ?', { plate, xPlayer.identifier })
  if not coche then return cb(false, 0) end

  cb(true, xPlayer.getMoney())
end)

Callback with validation

lua
-- Client: receives the two values
ESX.TriggerServerCallback('garaje:sacarCoche', function(ok, dinero)
  if ok then
    print('Vehicle taken out. You have ' .. dinero .. '€ left')
  else
    print('That vehicle is not yours')
  end
end, 'ABC123')

Client

Rule: in ALL paths of the callback (including the early returns) you must call cb(). Otherwise, the client is left hanging waiting for the response.

Practice what you learned

0/3
Test

¿Qué pasa si un ESX.RegisterServerCallback hace un 'return' temprano sin llamar a cb()?

Pista

El cliente está esperando la respuesta del callback.

Rellena los huecos

Completa el callback para que responda en TODOS los caminos y devuelva el dinero del jugador.

1ESX.RegisterServerCallback('garaje:sacarCoche', function(source, cb, plate)
2 local xPlayer = ESX.GetPlayerFromId(source)
3 if not xPlayer then return (false, 0) end
4 cb(true, xPlayer.())
5end)
Pista

Incluso en el return temprano hay que llamar a cb(); el saldo se lee con getMoney().

Corrige el error

Este callback deja al cliente colgado cuando el jugador no existe. Arréglalo para que responda en ese camino con cb(false).

Este código tiene un fallo:

1ESX.RegisterServerCallback('licencia:tiene', function(source, cb)
2 local xPlayer = ESX.GetPlayerFromId(source)
3 if not xPlayer then return end
4 cb(true)
5end)

Reescríbelo corregido:

Pista

Cambia 'return end' por 'return cb(false) end'.

Challenge: code it yourself

Write a callback that checks if the player has a license (in the DB) and returns true/false + the license name.

Write it yourself in your editor (VS Code) and test it on your server. You learn here by doing it, not by copying.

See hint

MySQL.single.await + cb on every return, including the error case.

Escribe aquí tu solución:

How was this lesson?