Skip to main content

Type Checking

NetRay includes an optional, built-in type checking system to help ensure the integrity of data sent over the network. By defining the expected structure and types for your events and requests, NetRay can automatically validate incoming payloads, catching potential errors early.

Defining Types

Type definitions are provided as tables within the options argument when registering an event or request.

  • typeDefinition: Validates data received by OnEvent.
  • requestTypeDefinition: Validates data received by OnRequest.
  • responseTypeDefinition: Validates the data returned from an OnRequest handler before sending it back.

The keys of the definition table are the expected field names in your data payload. The values are strings defining the expected type.

-- Example for RegisterEvent or RegisterRequestEvent options
local eventOptions = {
typeDefinition = {
id = "number", -- Must be a number
name = "string", -- Must be a string
level = "?number", -- Optional number (can be nil or number)
position = "Vector3", -- Must be a Vector3
isActive = "boolean", -- Must be a boolean
inventory = "Array<number>", -- Must be an array where all elements are numbers
config = "Dict<string, any>", -- Dictionary with string keys, any value type
target = "Instance<BasePart>|nil" -- Must be a BasePart instance OR nil
}
}

local requestOptions = {
requestTypeDefinition = {
action = "string"
},
responseTypeDefinition = {
status = "string",
timestamp = "number"
}
}

Supported Type Strings

NetRay's TypeChecker supports a range of type definitions:

Type StringDescriptionExample Value
stringStandard Lua string"hello"
numberStandard Lua number (integer or float)123, 3.14
booleanStandard Lua booleantrue, false
nilMust be nilnil
tableAny Lua table (use array, Dict for specifics){}
functionA Lua function (rarely needed over network)function() end
userdataAny Roblox userdata (use specific types below)Instance.new("Part")
threadA Lua thread/coroutinecoroutine.create(...)
anyAllows any type (bypasses checking)(Any value)
?typeNameOptional: Allows nil or typeNamenil, "world" for ?string
type1|type2Union: Allows type1 or type210 or "ten" for `number
Vector2Roblox Vector2Vector2.new(1, 2)
Vector3Roblox Vector3Vector3.new(1, 2, 3)
CFrameRoblox CFrameCFrame.new()
Color3Roblox Color3Color3.new(1, 0, 0)
BrickColorRoblox BrickColorBrickColor.Red()
UDimRoblox UDimUDim.new(0, 10)
UDim2Roblox UDim2UDim2.new(0, 10, 1, 0)
RectRoblox RectRect.new(0, 0, 10, 10)
Region3Roblox Region3Region3.new(v1, v2)
NumberSequenceRoblox NumberSequenceNumberSequence.new(0)
ColorSequenceRoblox ColorSequenceColorSequence.new(c3)
EnumItemAny Roblox EnumItemEnum.KeyCode.E
bufferRoblox buffer typebuffer.create(10)
InstanceAny Roblox InstanceInstance.new("Part")
Instance<ClassName>Specific Roblox Instance type or descendantPart matches Instance<BasePart>
Array<ItemType>Table with sequential int keys, all values match ItemType{1, 2} for Array<number>
Dict<KeyType, ValType>Table where all keys match KeyType, values match ValType{ a=1 } for Dict<string, number>

Note: Nested types like Array<Dict<string, ?number>> are supported.

How Validation Works

  • When NetRay receives data associated with a typeDefinition (or req/res variants):
    1. It checks if all non-optional keys defined in the schema are present in the received data.
    2. For each present key, it verifies the value's type against the corresponding type string in the schema using TypeChecker.isType.
  • If validation fails:
    • An informative warning is printed to the console (by default).
    • The OnEvent or OnRequest handler associated with that specific event/request instance will not execute for that particular invalid payload. Processing of other valid payloads continues normally.
    • For RequestClient, a validation failure before sending will reject the Promise.
    • For ClientEvent, a validation failure before sending will error.

Benefits

  • Catch Errors Early: Identify incorrect data structures during development or testing.
  • Improve Reliability: Prevent handlers from processing malformed data, reducing runtime errors.
  • Code Clarity: Type definitions serve as documentation for your network interfaces.

Limitations

  • Performance: Validation adds a small overhead. While cached, complex validation on very frequent events might be noticeable. Profile if needed.
  • Strictness: The default behavior is to warn and drop the message on failure. Currently, there isn't a built-in option to configure strict erroring instead of warnings on receive (though sending errors/rejects). This could potentially be added or implemented via Middleware.
  • any Type: Use any sparingly, as it bypasses type checking for that field.