-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Suggested API change #1
Comments
Here is high-level let conns = {
'domain1': new OadaWs('domain1'),
'domain2': new OadaWs('domain2')
};
let workers = [
{
serviceName: 'myCoOlSeRvIcE',
domain: 'domain1',
token: 'verySecure',
work: (job: OadaChane, oada: OadaClient) => { /* ... */ }
},
{
serviceName: 'mylesscoolservice',
domain: 'domain2',
token: '1337',
work: (job: OadaChane, oada: OadaClient) => { /* ... */ }
},
}
workers.forEach((worker) => {
let conn = conns[worker.domain];
conn.connect(worker.token)
.watch(`/bookmarks/services/${worker.serviceName}`)
.on('add', (job: OadaChane, oada: OadaClient) => {
worker.work(job, oada.clone());
});
}); |
Actually, I just realized I don't need workers.forEach((worker) => {
let conn = conns[worker.domain];
conn.connect(worker.token)
.watch(`/bookmarks/services/${worker.serviceName}`)
.on('add', (job: OadaChane, oada: OadaClient) => {
worker.work(job, conn.connect(worker.token));
}); as long as 'connect' stays very light. I'm thinking 'connect' just creates an 'OadaClient' adds a reference of 'conn' internally and copies the token. Basically the same work 'clone' would need to do at this point. |
Please stop calling the tokens barriers. They are bearer tokens |
As for the return types of |
@awlayton What? The only use of "barriers" that I find is correct. The intention behind |
@abalmos I am fine with your proposed API. If we decide to change it, I would prefer not to keep the 'oada-cache' style API because maintaining multiple APIs is sometimes a pain... |
@abalmos Currently, |
@awlayton Yes, we could do that. Would you like to contribute...? |
I'm not sure. The problem with that model is you get good feelings at compile time and forgot to add checks for runtime (also makes it hard to not allow Could something like this work (haven't had a chance to play with it, which is why I didn't originally suggest it). Seems like it should. function<T> get(path: string; isType: (data: any) => is a T) {
const data = get(path);
if (isType && !isType(data)) {
throw "Not the right type";
} else {
return data;
} That, of course, can be called without the typeguard check but at least if you /can/ give one. I suppose it would be called like this: const blah = wait oada.get("/bookmarks/blah", isBlah); Where I think TS will call |
If we can come to a reasonable answer to typing |
you said "provide some barriers" and then gave it a bearer token. |
If you are wanting runtime checking of the responses then we could use the content type of the response to find the appropriate schema and check again that. |
Or yes we can just pass in a runtime check function and infer the type from that. |
It doesn't quite work as I had hoped in |
Have you played with this much? I have been wondering how it will work from TS side. Here is what I mean (and maybe I am just misunderstanding). Let's say that const data = oada.get('/bookmarks/services/serviceA'); should result in console.log(data.name); How does TS know this is okay at compile time? Or do you have to give a hint like: const data = oada.get('/bookmarks/services/serviceA', 'application/vnd.oada.serviceA'); |
It would not work in that case no. A case where it does work if where you are expecting a specific set of content types so you can then use them is conditions const {data, headers} = axios.get('/boomarks/foo')
switch (headers['content-type']) {
case: 'application/vnd.foo':
assert('application/vnd.foo', data))
const foo = data // Has type Foo
// Do stuff with a Foo
break
case 'application/vnd.bar':
assert('application/vnd.foo', data))
const bar = data // Has type Bar
// Do stuff with a Bar
break
} As to how that manifests in the API of this library I am not sure. |
I am not more in love with this option than inferring the type from a validation function, I just wanted to list it. I'm not sure which is better. You could perhaps support either method, but that might be overkill. |
Some gut reaction thoughts:
@awlayton will @oada/types let us fetch a type guard based on content-type? If so, we could do two things:
How about this: I'll work on a PR for this API surface, typed with option 2 above and then open an issue to track @oada/types and reconsider? |
You cannot fetch a specific type guard function from a content type currently, I suppose that could be added. But you can already use the validate function with a content type rather than a schema id and if you have imported the corresponding types then there is an override that will tell TS that validate with that id asserts the corresponding type. |
Sorry if I am being dense, but are you saying this would be compatible with @oada/types: function<T> get(path: string; assertType: (resource: any) => asserts resource is T) {
const data = axios.get(path);
assertType(data);
return data;
} and used like: import { types } from '@oada/types'
const r = oada.get('/bookmarks/services/serviceA', types.assertType('application/vnd.oada.serviceA')); Or maybe even import { types } from '@oada/types'
function<T> get(path: string; assertType: (resource: any) => asserts resource is T | string) {
const data = axios.get(path);
if (typeof contentType === 'string') {
types.assertType('application/vnd.oada.serviceA')(data);
} else {
assertType(data);
}
return data;
} Of course I am guessing at the @oada/types API. Is that available in some pre-form that I could develop this PR off of? |
There is no method like You can do this: import types from '@oada/types'
types.validate('application/vnd.oada.bookmarks.1+json', data) // Returns true or false Also, currently if you import the type definition corresponding to the content type, TS will understand the type being checked. import types from '@oada/types'
// Importing types adds type overrides for the validate function with their id / content type
import Bookmarks from '@oada/types/oada/bookmarks'
if (types.validate('application/vnd.oada.bookmarks.1+json', data)) {
// TS will know data is a Bookmarks inside this if
} I need to rework the structure to make TS understand all the types without having to import them all. There is a WIP version of @oada/types on github. |
Also, if you know the type you want to assert, you do not need to bother with the content type: import Bookmarks, { assert } from '@oada/types/oada/bookmarks'
assert(data) // Asserts data is a Bookmarks |
Interesting, so maybe something like this would work then function<T = any> get(path: string; assert?: (resource: any) => asserts resource is T) {
const data = axios.get(path);
assert && assert(data);
return data;
} import Bookmarks, { assert } from '@oada/types/oada/bookmarks'
const r = oada.get<Bookmarks>('/bookmarks/services/serviceA', assert) It is a little clunky but has benefit of allowing a local If import { assert } from '@oada/types/oada/bookmarks'
const r = oada.get('/bookmarks/services/serviceA', assert) I suppose you will normally need to rename the |
That works as well already, you do not have to import the type for the assert function to work. That was just in my example from copy pasta. |
Also, there is a type in @oada/types for the assertion functions: import type { TypeAssert } from '@oada/types'
async function get<T = any> (path: string, assert?: TypeAssert<T>): Promise<T> {
const { data } = await axios.get(path);
assert ?? assert(data);
return data;
} |
I was thinking this would be a good time make API changes if we want. We can maintain an external layer that presents an 'oada-cache' style API ... with the hope that a new API is cleaner (more typeable) and eventually wins.
Here is an example of the API that comes to mind. This is driven by my use case in 'oada-jobs'. Would love to have a discussion on this. If you are agreeable, I would be happy to help make it so.
EDIT: Removing
clone
andsetToken
as they are not needed. We will makeconn.connect()
"cheap" instead.The text was updated successfully, but these errors were encountered: