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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Register plugin within namespace #5251

Open
2 tasks done
matthyk opened this issue Jan 3, 2024 · 8 comments
Open
2 tasks done

Register plugin within namespace #5251

matthyk opened this issue Jan 3, 2024 · 8 comments
Labels
feature request New feature to be added

Comments

@matthyk
Copy link
Contributor

matthyk commented Jan 3, 2024

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the feature has not already been requested

馃殌 Feature Proposal

In some situations, it would be helpful to register plugins within a namespace. This could be helpful in different situations when organising plugins. For example, when versioning plugins or grouping plugins that are related.

Motivation

See Feature Proposal but this feature could also work very well in combination with @fastify/autoload. For example, if you use @fastify/basic-auth and @fastify/jwt in a project, it would be an improvement if both were under the namespace auth. The usage would then be fastify.auth.sign({ payload } ) instead of fastify.sign({ payload } ) respectively fastify.auth.basicAuth instead of fastify.basicAuth.

Example

const fp = require('fastify-plugin')
const Fastify = require('fastify')

const v1ApiPlugin = fp(function(instance, opts, done) {
    // Say hello to v1 API, e.g. POST /api/v1/sayHello
    instance.decorate('sayHello', () => {})
    done()
})

const v2ApiPlugin = fp(async function(instance, opt, done) {
    // Say hello to v2 API, e.g. POST /api/v2/sayHello
    instance.decorate('sayHello', () => {})
    done()
})

const app = Fastify()

app.register(v1ApiPlugin, {
    namespace: 'api.v1' // <-- new register options
})
app.register(v2ApiPlugin, {
    namespace: 'api.v2' // <-- new register options
})

app.ready(() => {
    app.api.v1.sayHello()
    app.api.v2.sayHello()
})
@Eomm
Copy link
Member

Eomm commented Jan 3, 2024

I love this idea
We could ship in v4 too, but the namespace prop could be dangerous so I would go with something like pluginNamespace and then namespace in v5.

It is doable, but:

  • quick win: when you don't break the encapsulated context should be quite "quick" to implement (eg: your example without the fp)
  • harder win: when you break the encapsulation, instance is app actually, so you need to tweak the argument to make it works

@Eomm Eomm added the feature request New feature to be added label Jan 3, 2024
@mcollina
Copy link
Member

mcollina commented Jan 3, 2024

I agree, it would simplify quite a lot of logic in some plugins. However this is quite tricky to implement due to how plugins work.
In other terms, it's hardly doable 馃槶. There are a few ways in which this could be done... but it's going to be very hard.

This is usually one of the feature requests I would take to implement in avvio (given the fact that avvio is a mess), but I don't think I have the bandwidth.

Moreover, it'd be a mess with TS, which has quite a lot of users and demand.

@matthyk
Copy link
Contributor Author

matthyk commented Jan 3, 2024

@mcollina @Eomm A bit off-topic, but has the Fastify Org ever thought about applying to Google Code of Summer? This would be a good opportunity to implement such feature requests, which are likely to take quite a long time.

@metcoder95
Copy link
Member

But the decoration happens within fastify isn't it?

I like @Eomm idea, potentially fp will need to also go through some work (maybe get in sync with fastify towards the rollout of the feature).

What's missed within avvio to enable this feature? 馃

@Uzlopak
Copy link
Contributor

Uzlopak commented Jan 3, 2024

I dont like this feature tbh.

@Eomm
Copy link
Member

Eomm commented Jan 6, 2024

I change my mind 馃槃

Let's see this real example:

test('plugin namespace', async t => {
  t.plan(2)
  const app = Fastify()

  await app.register(async function plugin (app, opts) {
    app.decorate('utility', function () {
      return 'utility'
    })

    app.get('/', function (req, reply) {
      // ! here the plugin would use app.utility()
      // ! the plugin does not know about the namespace
      reply.send({ utility: app.utility() })
    })
  }, { namepace: 'foo' })

  // ! but outside the plugin the decorator would be app.foo.utility()
  t.ok(app.foo.utility)

  const res = await app.inject('/')
  t.same(res.json(), { utility: 'utility' })
})

TLDR:

  • the same decorator would have two different interfaces:
    • one inside the plugin
    • one outside the plugin

@mcollina
Copy link
Member

mcollina commented Jan 6, 2024

I think this is possible, even in v4.

@mcollina
Copy link
Member

mcollina commented Jan 8, 2024

This is a widespread pattern:

https://github.com/fastify/fastify-swagger-ui/blob/3cf8d5ddd22304c516b5aa2c413c89f74f769889/index.js#L8-L28

We are looking for a way to automate it and simplify its usage.

@mcollina mcollina added v5.x Issue or pr related to Fastify v5 and removed v5.x Issue or pr related to Fastify v5 labels Jan 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature to be added
Projects
None yet
Development

No branches or pull requests

5 participants