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

[FEATURE] The future of glee as a framework #828

Open
KhudaDad414 opened this issue Jun 10, 2024 · 3 comments
Open

[FEATURE] The future of glee as a framework #828

KhudaDad414 opened this issue Jun 10, 2024 · 3 comments
Labels
enhancement New feature or request

Comments

@KhudaDad414
Copy link
Member

KhudaDad414 commented Jun 10, 2024

Context:

following #795
Glee is a great tool for API-first development, but it hasn't gained much traction. I believe the issues are mostly::

  • Shallow learning curve: due to limiting the user to use rigid file structure for operations, lifecycles, and authentication.
  • Difficulty in managing a global state: Each operation/lifecycle function must be in its file, it makes having a centralized state harder.
  • Can only be used in the node environment

Proposed Solution:

Get Rid of File-based routing: To be honest, I don't see why we are forcing users to have functions and lifecycles folders and follow a rigid file-based operation handlers structure.

Frameworks like Next.js use folders since they have a good excuse for it, (ie, file-based routing) but Glee is more like Express.js, at the end user only needs to pass operation handlers and we take care of the rest.

Adapters should be separate packages: By having adapters as separate packages their development can be more streamlined, and they can be maintained by their respective contributors. plus user can write their adapter and plug it in.

It will help us run glee in the browser as well as the node environment, given the provided adapter supports it.

How should it look like:

an example demonstrating how the glee interface should look like:

import { Parser } from '@asyncapi/parser';
import { WSServerAdapter } from 'Aasyncapi/glee-adapters-ws';
import { Glee } from '@asyncapi/glee';
import type { Context, Message } from '@asyncapi/glee';


//parse the asyncapi file
const parser = new Parser()
const file = await Bun.file('asyncapi.yaml').text()
const {document} = await parser.parse(file)
if(!document) throw new Error('Invalid asyncapi file')

//Initialize the Glee instance
//GleeOptions will include the configuration that we do with glee.config.js and .env file.
const glee = new Glee(document, {}: GleeOptions)

//Add the adapter
glee.use(new WSServerAdapter({}: AdapterOptions))

//Add the operation handler
glee.use('hello', (message: Message, context: Context) => {
  console.log('Received:', message.payload)
  //this is how we reply to the message
  message.reply('world')
  //this is how we send a message to a specific server
  context.send('server-id', 'message to server-id')
})


//Add event listeners
glee.on('connection:open', ({connection, serverId}) => {
  // A connection has been established to one of the servers
})

glee.on('connection:close', ({connection, serverId}) => {
  // A connection has been closed
})


glee.connect()

Adapters are required to Extend this class:

  • the events that they can emit are standardised.
  • The protocols and the environment that they can run should be specified.
import { EventEmitter } from 'events'
import { GleeError } from '../Errors'
import type { ServerInterface } from '@asyncapi/parser'
import { AsyncAPIServer } from '../ServerWrapper'
import type { Message } from '../Message'
import type { WebSocketConnection } from './ws/server'



interface AdapterEvents {
  'connection:open': (connection: WebSocketConnection) => void,
  'connection:close': (connection: WebSocketConnection) => void,
  'server:listening': () => void
  'server:shutdown': () => void
  'error': (error: GleeError) => void,
  'message': (message: Message) => void,
}


interface AdapterEvent {
  connection: Connection
  serverId: string
}

enum Environment {
  BROWSER = 'browser',
  NODE = 'node'
}

export class Adapter extends EventEmitter {

  protected _asyncAPIServer: AsyncAPIServer

  emit<U extends keyof AdapterEvents>(event: U, ...args: Parameters<AdapterEvents[U]>): boolean {
    return super.emit(event, ...args)
  }
  on<U extends keyof AdapterEvents>(event: U, listener: AdapterEvents[U]): this {
    return super.on(event, listener)
  }


  constructor(server: ServerInterface) {
    super()
    this._asyncAPIServer = new AsyncAPIServer(server)
  }

  async connect(): Promise<Adapter> {
    try {
      return this._connect()
    } catch (e) {
      const errorMessage = `Unable to establish a connect to ${this.name()}.`
      this.emitError(new GleeError({name: 'SERVER_SERVE_ERROR', message: errorMessage, cause: e}))
    }
    return this
  }
  
  protected _connect(): Adapter{
    throw new Error('Method not implemented.')
  }

  name(): string {
    throw new Error('Method not implemented.')
  }

  send(message: Message): void {
    throw new Error('Method not implemented.')
  }

  protected emitMessage(message: Message) {
    this.emit('message', message)
  }

  protected emitServerListening() {
    this.emit('server:listening')
  }

  protected emitServerShutdown() {
    this.emit('server:shutdown')
  }

  protected emitConnectionOpen = ({connection}: AdapterEvent) => {
    this.emit('connection:open', connection)
  }

  protected emitConnectionClose = ({connection}: AdapterEvent) => {
    this.emit('connection:close', connection)
  }

  emitError(error: GleeError) {
    this.emit('error', error)
  }

  supportedProtocols(): string[] {
    throw new Error('Method not implemented.')
  }

  supportedEnvironments(): Environment[] {
    throw new Error('Method not implemented.')
  }

} 

Technical changes:

  • Convert glee to a monorepo: we can release the Adapters separately and utilities like validators can have their package.
  • use PNPM: it works better with mono repo.
@KhudaDad414 KhudaDad414 added the enhancement New feature or request label Jun 10, 2024
@oviecodes
Copy link
Contributor

@KhudaDad414 what's the update, how do we proceed on this issue?

@KhudaDad414
Copy link
Member Author

@oviecodes I am currently waiting for some feedback from the community. Maybe we can discuss it in the DX working group.

@Souvikns
Copy link
Member

I like the idea of removing file-based routing, as by removing it we can use glee on the browser as well.

glee.use(new WSServerAdapter({}: AdapterOptions))

I think we should use some adapters out of the box, and the user can over-write them or add new adapters, so no idea to create a mono-repo.

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

No branches or pull requests

3 participants