Code Snippets
/

Proxy Patterns: Validation, Logging, Defaults

Proxy Patterns: Validation, Logging, Defaults

`Proxy` lets you intercept the basic operations on an object (get, set, has, deleteProperty) and run your own logic before or instead of the default behavior. This snippet shows three of the most useful patterns: a validating Proxy that rejects bad writes at the source, a logging Proxy that records access for debugging, and a defaults-plus-locked Proxy that supplies fallbacks and freezes keys after init. Use sparingly because Proxy adds a small per-access cost; reach for it when you need cross-cutting policy on a plain data object.

JavaScript
Hard
js-proxy-reflect
references
design-patterns

1,018 views

21

function makeConfig(initial) {
    const schema = {
        port: (v) => Number.isInteger(v) && v > 0 && v < 65536,
        host: (v) => typeof v === 'string' && v.length > 0,
        debug: (v) => typeof v === 'boolean',
    };
    return new Proxy({ ...initial }, {
        set(target, key, value) {
            const validate = schema[key];
            if (!validate) throw new TypeError(`unknown config key: ${String(key)}`);
            if (!validate(value)) {
                throw new TypeError(`invalid value for '${String(key)}': ${JSON.stringify(value)}`);
            }
            target[key] = value;
            return true;
        },
    });
}

const config = makeConfig({ port: 3000, host: 'localhost', debug: false });
config.port = 8080;
console.log(config.port); // 8080

try { config.port = 70000; } catch (e) { console.log(e.message); }
// invalid value for 'port': 70000
try { config.timeout = 5000; } catch (e) { console.log(e.message); }
// unknown config key: timeout

The set trap runs in place of the default [[Set]] operation, so you can validate value before letting the write land on the target object. Returning true signals success; throwing or returning false rejects the assignment (in strict mode, false becomes a TypeError automatically). Notice that the target is a copy of initial, so the Proxy never mutates the caller's object. This pattern is great for config objects, public DTOs, and anywhere a typo or out-of-range value would only show up much later as a bug; the Proxy turns silent corruption into a loud, immediate error.

2 more snippets in this entry are available for premium members.

Upgrade to Premium