Hey guys, my name is Akash Joshi. I'm a software engineer at SIGTECH and today I'm going to talk about unleashing object proxies, building type-safe wrappers for anything. Object proxies are an amazing tool that are severely under-explored but are quite widely used in all of the libraries that we use in our day-to-day. So I'm going to explain how they work, what they are and how you can use them as well.
So what are object proxies? Object proxies are basically middleware for your objects. So think of them as a wrapper around your object with which you can control what input comes into the object and what you return from the object whenever a user tries to access a method or a property. So what are some of the use cases that we see with object proxies in the real life? So one of the first use cases that one can think of is controlling data access. So doing input validation or implementing an access control layer on any sort of object which can contain privileged properties. So for example, on a bank, if you want to create an object which contains the user's data then based on whether a user has, one of your developers have, access to that property or not, you can actually do input validation on it. So if the user or the developer has access to that property, then you return it, otherwise you can return an error or whatever you want to do instead.
Similarly, you can add logging to your objects via object proxies. So if a user tries to repeatedly access an unauthorized data, or you just want to have a log of all of the activities that your developers are doing on any privileged object, then you can use, you can add logging to it by object proxies. Any accesses are logged to one of your access logs. But most importantly, what we use object proxies for is response handling. So this can involve returning something else based on what the user provides or lazy loading certain objects. So for example, just continuing with the user case. Let's say we have an object which contains a user's banking details, like their address history, their transaction history, anything. But you don't want to fetch all of it at runtime. So whenever someone tries to access their address history, then we make a network call to the address API, get all of that data, and then return it via the output. So on the on the developer side, it just looks like you made a property call, like a .call to an object. So that would be user.address. But in the backend, it will actually make an API call. And you can also implement caching and other things on top of it to actually make your object calls faster.
In the wild, object proxies are used by Prisma. So have you ever thought about how Prisma knows what all of your tables are and how it is able to access all of them at runtime, even though it actually isn't present in their codebase? What they do is they generate the types for all of your tables and then they apply them to an object proxy. So whenever you are accessing your property by using the dot method, so like prisma.analytics, prisma.user, prisma.posts, what it actually does is it makes a network call via object proxies to the actual database and then fetches those results and then returns them to your client. Of course, it isn't all hard-coded into the Prisma's codebase, but they generate it at runtime via TypeScript and then object proxies take care of the rest. Similarly for PRPC, PRPC works on a similar concept where they allow you to make object calls, make method calls, from your front end to your back end quite transparently. They use object proxies as well. They expose a router object on the back end and expose its types and then use those types on the front end.
Comments