Dynamic Fluent Interface for API calls (Powered by JS Proxy)

When working with REST APIs, having a clean, expressive client can greatly simplify how you write code. Imagine calling your API like this:

const api = createApi(‘localhost’);

api.users.get().then(console.log);
api.posts.post({ title: ‘Hello’ }).th…


This content originally appeared on DEV Community and was authored by Andrey Smolko

When working with REST APIs, having a clean, expressive client can greatly simplify how you write code. Imagine calling your API like this:

const api = createApi('localhost');

api.users.get().then(console.log);
api.posts.post({ title: 'Hello' }).then(console.log);

This syntax is not only clean but reads almost like a natural language. The secret behind this elegant interface? It’s all about dynamic property access powered by JavaScript’s Proxy object.

  • Resources like users and posts are not predefined properties of the api object.
  • HTTP methods like get and post are also dynamically resolved.

This means you don’t have to write boilerplate code to explicitly declare every resource or method. Instead, these identifiers are resolved at runtime!

The core enabler is Proxy

A Proxy lets you intercept fundamental operations on objects, such as property access or function calls, and define custom behaviors.

Here’s the minimal implementation of createApi:

const createApi = (domain, path = '') => {
  return new Proxy(() => {}, {
    get(target, key) {
      return createApi(domain, `${path}/${key.toString()}`);
    },
    apply(target, thisArg, args) {
      const i = path.lastIndexOf('/');
      const method = path.slice(i + 1).toUpperCase();
      const url =
        domain + (i === -1 ? '/' : path.slice(0, i));

      const options = {
        method,
        headers: {
          'Content-Type': 'application/json',
        },
      };

      if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(method) && args[0]) {
        options.body = JSON.stringify(args[0]);
      }

      return fetch(url, options).then((res) => {
        if (!res.ok) {
          throw new Error(`HTTP error! status: ${res.status}`);
        }
        return res.json();
      });
    },
  });
};

const api = createApi('localhost');

api.users.get().then(console.log);
api.posts.post({ title: 'Hello' }).then(console.log);

How It Works: get and apply traps explained

The get Trap — Capturing Property Access

  1. Every time you access a property on the proxy — like api.users or api.posts — the get trap intercepts that access.
  2. Instead of returning a fixed value, it calls createApi recursively, appending the accessed property name (users, posts, or HTTP methods like get, post, etc.) to the URL path argument.
  3. This recursive design enables infinitely deep property chains without needing to define them explicitly upfront.
  4. The recursion ends when the proxy is invoked as a function (via the apply trap), which triggers the actual HTTP request.

The apply Trap — Handling Function Calls

  1. When you finally call the proxy as a function — api.users.get() —the apply trap intercepts the call.
  2. It extracts the HTTP method from the last part of the path (like get, post, etc.), builds the full URL, and executes the HTTP request using fetch.

By combining the get trap for dynamic property access, the apply trap for function invocation, and recursion for building URL paths, this approach enables the creation of a powerful, flexible, and elegant API client.

Note: In JavaScript, a trap is a special method defined in a Proxy handler object. These traps intercept fundamental operations—like property access, function calls, or property assignments—allowing you to customize how those operations behave.

This post was inspired by the API design found in elysiajs/eden.


This content originally appeared on DEV Community and was authored by Andrey Smolko


Print Share Comment Cite Upload Translate Updates
APA

Andrey Smolko | Sciencx (2025-06-29T11:49:17+00:00) Dynamic Fluent Interface for API calls (Powered by JS Proxy). Retrieved from https://www.scien.cx/2025/06/29/dynamic-fluent-interface-for-api-calls-powered-by-js-proxy/

MLA
" » Dynamic Fluent Interface for API calls (Powered by JS Proxy)." Andrey Smolko | Sciencx - Sunday June 29, 2025, https://www.scien.cx/2025/06/29/dynamic-fluent-interface-for-api-calls-powered-by-js-proxy/
HARVARD
Andrey Smolko | Sciencx Sunday June 29, 2025 » Dynamic Fluent Interface for API calls (Powered by JS Proxy)., viewed ,<https://www.scien.cx/2025/06/29/dynamic-fluent-interface-for-api-calls-powered-by-js-proxy/>
VANCOUVER
Andrey Smolko | Sciencx - » Dynamic Fluent Interface for API calls (Powered by JS Proxy). [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/06/29/dynamic-fluent-interface-for-api-calls-powered-by-js-proxy/
CHICAGO
" » Dynamic Fluent Interface for API calls (Powered by JS Proxy)." Andrey Smolko | Sciencx - Accessed . https://www.scien.cx/2025/06/29/dynamic-fluent-interface-for-api-calls-powered-by-js-proxy/
IEEE
" » Dynamic Fluent Interface for API calls (Powered by JS Proxy)." Andrey Smolko | Sciencx [Online]. Available: https://www.scien.cx/2025/06/29/dynamic-fluent-interface-for-api-calls-powered-by-js-proxy/. [Accessed: ]
rf:citation
» Dynamic Fluent Interface for API calls (Powered by JS Proxy) | Andrey Smolko | Sciencx | https://www.scien.cx/2025/06/29/dynamic-fluent-interface-for-api-calls-powered-by-js-proxy/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.