I'm trying to make a JS Proxy that does this.
routes.api.posts => '/api/posts'
routes.api.posts('postId') => '/api/posts/postId'
routes.api.posts('postId', { name: 'alex' }) => '/api/posts/postId?name=alex'
routes.api.posts({ name: 'alex' }) => '/api/posts?name=alex'
I've referenced these
I've gotten this far.
var obj = {
func: undefined,
realFunc: (args) => args,
prop: undefined,
realProp: true
};
var handlers = {
path: '',
get: (target, name) => {
const prop = target[name];
if (prop != null) { return prop; }
let isProp = true;
Promise.resolve().then(() => {
handlers.path = `${handlers.path}/${name}`
console.log('handlers.path', handlers.path)
if (isProp) {
console.log(`props ${name}`)
} else {
// it's a function
console.log(`props ${name}`)
}
});
return new Proxy(() => {}, {
get: handlers.get,
apply: (a, b) => {
isProp = false;
return new Proxy(() => {}, handlers);
}
});
}
};
var routes = new Proxy(obj, handlers)
var case1 = routes.api.posts
console.log(`routes.api.posts()`, case1 === '/api/posts', case1)
var case2 = routes.api.posts('postId')
console.log(`routes.api.posts('postId')`, case2 === '/api/posts/postId', case2)
var case3 = routes.api.posts('postId', { name: 'alex' })
console.log(`routes.api.posts('postId'`, case3 === '/api/posts/postId?name=alex', case3)
var case4 = routes.api.posts({ name: 'alex' })
console.log(`routes.api.posts({ name: 'alex' })`, case4 === '/api/posts?name=alex', case4)
This seems to work well. get
intercepts missing props and creates new routes
objects on the fly, while apply
takes care of function calls.
let makeRoutes = (prefix = '') => new Proxy(() => {}, {
get(target, prop) {
if (prop === 'toString')
return () => prefix
if (prop in target || typeof prop !== 'string')
return target[prop]
return makeRoutes(prefix + '/' + prop)
},
apply(target, thisArg, args) {
let url = prefix
for (let a of args)
url += typeof a === 'object'
? '?' + new URLSearchParams(a)
: '/' + a
return url
},
})
let routes = makeRoutes()
console.log('' + routes.api.posts)
console.log('' + routes.api.posts('postId'))
console.log('' + routes.api.posts('postId', {name: 'alex'}))
console.log('' + routes.api.posts({name: 'alex'}))
console.log('' + routes.this.should.work.too('param', {name: 'alex'}))