# Design Patterns in Odoo: Proxy

> How the Proxy pattern controls access to an object, with two examples from Odoo's JavaScript: the localization object and reactive records in the mail store.

**Source:** <https://trobz.com/insights/design-patterns-odoo-proxy/>

---


If you work with JavaScript code in Odoo, you may come across `Proxy`. Proxy is a structural design pattern that provides a substitute for another object. A proxy controls access to the original object and can run extra logic before or after a request reaches it. Think of a security guard at a building entrance, who checks credentials before letting anyone in.

## Overview of the Pattern

Sometimes accessing an object needs extra logic: delaying initialization, restricting access, caching results or handling other concerns. Changing the original object directly is not always a good idea, because it complicates the code and breaks the single responsibility principle.

The Proxy pattern solves this with a proxy object that has the same interface as the original. Clients work with the proxy without knowing it isn't the real object, and the proxy manages access to the original, adding logic before or after it delegates the request.

## How to Implement It in JavaScript

JavaScript has a built-in `Proxy` object for this pattern. It takes two arguments:

- **Target**: the original object.
- **Handler**: an object that defines the custom behavior, through traps such as `get` and `set`.

### Example 1: Access Control in `localization`

In the web module, [`localization`](https://github.com/odoo/odoo/blob/209f9ea327d59c2583edf7399549dab66dc23d4b/addons/web/static/src/core/l10n/localization.js#L26) is a proxy object that holds the user's localization settings:

```javascript
export const localization = new Proxy(
    {},
    {
        get: (target, p) => {
            // "then" can be called implicitly if the object is returned in an
            // `async` function, so we need to allow it.
            if (p in target || p === "then") {
                return Reflect.get(target, p);
            }
            throw new Error(
                `could not access localization parameter "${p}": parameters are not ready yet. Maybe add 'localization' to your dependencies?`
            );
        },
    }
);
```

Its properties are filled in later by the [localization service](https://github.com/odoo/odoo/blob/209f9ea327d59c2583edf7399549dab66dc23d4b/addons/web/static/src/core/l10n/localization_service.js#L70):

```javascript
Object.assign(localization, {
    dateFormat,
    timeFormat,
    dateTimeFormat: `${dateFormat} ${timeFormat}`,
    decimalPoint: userLocalization.decimal_point,
    direction: userLocalization.direction,
    grouping: JSON.parse(userLocalization.grouping),
    multiLang: result.multi_lang,
    thousandsSep: userLocalization.thousands_sep,
    weekStart: userLocalization.week_start,
});
```

When code reads a property such as `localization.dateFormat`, the proxy intercepts the access. If the property has not been set yet, it throws an error instead of silently returning `undefined`, so bugs caused by uninitialized data surface early. The built-in `Reflect` API makes it simple to forward the access to the target object.

### Example 2: Reactivity and Lazy Computation in `mail`

In the mail module, records in the [store](https://github.com/odoo/odoo/blob/209f9ea327d59c2583edf7399549dab66dc23d4b/addons/mail/static/src/model/make_store.js#L57) are wrapped in proxies. The `get` trap handles lazy computation:

```javascript
get(record, name, recordFullProxy) {
    // ...
    if (Model._.fieldsCompute.get(name) && !Model._.fieldsEager.get(name)) {
        record._.fieldsComputeInNeed.set(name, true);
        if (record._.fieldsComputeOnNeed.get(name)) {
            record._.compute(record, name);
        }
    }
    // ...
    return Reflect.get(record, name, recordFullProxy);
},
```

When a computed field is not eager, the trap marks it as needed and computes its value only when it is read, which avoids unnecessary work.

The `set` trap is where it gets interesting:

```javascript
set(record, name, val, receiver) {
    // ...
    return store.MAKE_UPDATE(function recordSet() {
        // ...
        store._.updateFields(record, { [name]: val });
        // ...
        return true;
    });
},
```

Instead of assigning the value directly, it runs the update inside [`store.MAKE_UPDATE`](https://github.com/odoo/odoo/blob/209f9ea327d59c2583edf7399549dab66dc23d4b/addons/mail/static/src/model/store.js#L37), which batches several changes into a single update cycle so the UI can react to data changes efficiently.

## Pros and Cons

**Pros:**

- **Extra functionality**: validation, security checks or caching can be added without changing the original code.
- **Lazy initialization**: expensive objects or values are created only when they are needed.
- **Separation of concerns**: add-on behavior stays separate from core business logic.

**Cons:**

- **More complexity**: the extra layer can make debugging harder.
- **Performance overhead**: every intercepted operation adds a small cost.

## Conclusion

The Proxy pattern gives Odoo's JavaScript code a way to control and extend how objects behave without modifying the objects themselves. Whether for lazy computation, validation or guarding data that is not ready yet, as with localization, proxies help keep the code robust and maintainable.

## References

- Patterns.dev, [Proxy Pattern](https://www.patterns.dev/vanilla/proxy-pattern/).

