Skip to content
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

Enhance Service Provider to Support Chained Parsing Methods #858

Open
maryam4s26 opened this issue Sep 15, 2024 · 10 comments
Open

Enhance Service Provider to Support Chained Parsing Methods #858

maryam4s26 opened this issue Sep 15, 2024 · 10 comments
Labels

Comments

@maryam4s26
Copy link

hello @andersevenrud.
I reviewed the section on creating a service provider in the osjs documentation.

// src/client/myprovider.js
export class MyApiServiceProvider
{
  constructor(core, options = {}) {
    this.core = core;
    this.options = options;
  }

  provides() {
    return ['namespace/api'];
  }

  async init() {
    this.core.singleton('namespace/api', () => ({
      greet: name => alert(`Hello ${name}!`)
    }));
  }
}

// src/client/index.js
import {MyApiServiceProvider} from './myprovider.js';

// ...
osjs.register(MyApiServiceProvider);
// ...

This service provider is called as follows:

OSjs.make('namespace/api').greet('World');

But I want to have a service provider that can be called this way:

OSjs.make('namespace/api').greet('World').firstParser();
OSjs.make('namespace/api').greet('World').secoundParser();
@andersevenrud
Copy link
Member

andersevenrud commented Sep 15, 2024

Just use a higher order function:

    this.core.singleton('namespace/api', () => ({
      greet: name => () => {
         return { firstParser: () => {} }
      }
    }));

@maryam4s26
Copy link
Author

this.core.singleton('namespace/api', () => ({
greet: name => () => {
return { firstParser: () => {} }
}
}));

But in this case, it cannot be called as below and we have an error.

await core.make('namespace/api').greet('World').firstParser();

server log is:
bash WARN core.make(...).greet(...).firstParser is not a function packages 21:03:17

It can only be called as follows:

const result = await core.make('namespace/api').greet('World');
const firstParserResult = result.firstParser();

@andersevenrud
Copy link
Member

andersevenrud commented Sep 15, 2024

It is because of the await keyword. You need to wrap the promise:

(await core.make('namespace/api')).greet().firstParser()

@andersevenrud
Copy link
Member

You actually do not need the await here, your operations are synchronous.

@andersevenrud
Copy link
Member

If you do have all async operations then you have to do either await wrapping or use then, I.e.:

this.core.singleton('namespace/api', () => ({
      async greet: name => () => {
         return { async firstParser: () => {} }
      }
    }));
await (await core.make('namespace/api').greet()).firstParser()

// or
core.make('namespace/api').greet().then(res => res.firstParser)

Just standard js async stuff :)

@maryam4s26
Copy link
Author

Isn't this a better syntax?

export class MyApiServiceProvider
{
  constructor(core, options = {}) {
    this.core = core;
    this.options = options;
  }

  provides() {
    return ['namespace/api'];
  }

  async init() {
    this.core.singleton('namespace/api', () => ({
      greet: name => this.greet(name)
    }));
  }
  
  async greet(name) {
  const result = `hi + ${name}`
  // Return an object with chainable methods
  return {
    fistParser: () => this.fistParser(result),
    secoundparse: () => this.secoundParse(result),
  };
}

  fistParser(input) {
    // Define your first parsing logic here
    console.log('first parse: ', input);
    return {parsed: 'first', output: input};
  }

  secoundParser(input) {
    // Define your secound parsing logic here
    console.log('secound parse: ', input);
    return {parsed: 'secound', output: input};
  }
  
}

@maryam4s26
Copy link
Author

maryam4s26 commented Sep 15, 2024

this.core.singleton('namespace/api', () => ({
greet: name => () => {
return { firstParser: () => {} }
}
}));

I use your code, but in the log I have the following value:

bash WARN core.make(...).greet(...) is not a function packages 21:03:17

@andersevenrud
Copy link
Member

andersevenrud commented Sep 15, 2024

Isn't this a better syntax?

How you write stuff is up to you. I just provide examples.


Working example of what I've written above: https://codesandbox.io/p/sandbox/blue-cherry-9zqzlz?file=%2Fsrc%2Findex.js%3A35%2C1-36%2C1&workspaceId=17bde2a4-055b-48f4-944a-81ffb405ae07

This should print "Hello World Sync" from a sync chained provider, and "Hello World Acync" of the same, but chained async.

NB: You have to open browser devtools console to see the messages

@andersevenrud
Copy link
Member

andersevenrud commented Sep 15, 2024

FYI: There is no special "OS.js stuff" going on here. A service provider simply provides an object, function or whatever you define in the registration (instance/singleton) callback. How this is implemented and consumed is fully up to you.

@andersevenrud
Copy link
Member

andersevenrud commented Sep 15, 2024

Isn't this a better syntax?

If you look at the internal implementation of these providers, you'll se that a "contract" pattern is used to make it easier to maintain. Examples:

This can be abstracted further with other patterns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants