Client Methods

Any function declared in a Service's Client table or with function MyService.Client:MethodName(...), same thing becomes a RemoteFunction the client can call. Unlike a Signal (fire-and-forget) or a Property (persistent state), a Client method is a genuine request/response: the client asks for something, the server computes an answer, the client gets it back.

Server side

function MyService.Client:RequestTrade(plr: Player, targetName: string): boolean
    -- > // 'plr' is injected by Owl, it's always the player who made the call (For the beginners, you still do put plr as first argument)
    local token = Owl.GetPlrToken(plr)
    if not token then return false end
 
    return processTradeRequest(plr, targetName)
end

Owl always injects the calling Player as the first argument automatically, on the server side only you never pass it yourself when calling from the client and you can't spoof someone else's Player object by passing a different one, since Owl supplies it from the actual remote invocation, not from a client-controlled argument. See Services for more on why Owl.GetPlrToken(plr) is worth calling on top of that for anything sensitive.

Client side

Calls are asynchronous and return a Promise there's no blocking :InvokeServer()-style call anywhere in Owl.

self.MyService:RequestTrade("PlayerName")
    :andThen(function(success)
        print("Trade accepted:", success)
    end)
    :catch(function(err)
        warn("Error:", err)
    end)

Always attach a :catch(...). If the server-side method throws or the request times out, an unhandled promise rejection fails silently by default, you'll see nothing in the output and spend time debugging a request that never seemed to happen.

If you find yourself reaching for a Client method just to fetch a value that rarely changes (a player's current level, say), consider a Property instead one Observe call replaces a fresh RemoteFunction round-trip every time the UI needs to redraw. Client methods are the right choice for one-off actions (buy this item, request this trade) rather than for continuously reading state.

Where to go next

  • Properties and Signals - the other two communication abstractions and when each fits better than a Client method.
  • Middleware - how requests to a Client method get filtered before your function even runs.
  • TypeChecker - validating a Client method's incoming arguments automatically, instead of hand-checking types at the top of every method.