You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This discussion is meant to discuss/propose/modify the API of Elysia to handle event, schema and macro hooks consistently across different scopes.
With the recent introduction of the Macro API as an encapsulation of lifecycle hook handlers I wanted to raise a concern of implicitness and complexity. Prior there was already some mixed handling in regards to lifecycle processing and schemas (as a higher level abstraction on top of those). That said the later are certainly useful as a common pattern which provide not just a convenient shortcut but even more strong-type safety for requests and responses using Eden. In general they work fine.
Though based on the documentation and usage via code it is not directly transparent what their relation is. In general events, macros and schemas are all applied as hooks throughout the lifecycle of an incoming connection. Each of them can be defined at different levels as:
Especially on the local layer there can be now an 'overloading'as macros can be defined. Therefore I wanted to suggest the following for better readability and composability:
Ensure parity of definition in the code and comments. Currently the annotations include examples referring to schema: {...} for the local hooks, scoped guards etc. even though it is not supported. While not many might take a look at those it's certainly helpful to have valid ones set, preferably matching the ones in other documented places.
Have the 3rd parameter of a route handler referred for lifecycle/hook operations with a structured interface to easier distinguish them. At the moment custom names of macro definitions are placed side by side with event processors like afterHandle as well as schema validations such as body. Each of them is part of the lifecycle/hook stack but they are different abstractions which are not equally essential as the baseline (even more for custom macros). By having an envelope this can be easier communicated while also making it easier to share respective definitions between scoped and global handlers.
Align the structure within the schema interface (which is used for the .schema(...) global handler as well as the schema field of the local route hook) so that there is a clear separation for request and response. This way response doesn't feel like an afterthought being attached to query, params or body but is at a similar level as there is a request envelope for those fields. Later on there might even be additional validation schemas for outgoing cookie values with a familiar structure. Or there can be additional detail for better documentation of a response for a specific status code.
newElysia().get('/id/:id',({ cookie })=>{// in case of the extend long example:// cookie.token.value = 'authentication-token-value';return'Hello World!';},{schema: {request: {query: t.Object({name: t.String()}),params: t.Object({id: t.Numeric()}),},response: t.String()/** * alternative extended long example with more options similar to `request` * * response: { *. 200: { *. cookie: { *. token: t.String() * }, * body: t.String(). * } */}}})
Doing those will make the usage more verbose but in return should prevent confusion as its easier to reason how something gets set. Finally on the internal side it can help to share interfaces while avoiding collisions. In return the additional nesting layer might be convoluted for simple definitions its about balancing.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
With the recent introduction of the Macro API as an encapsulation of lifecycle hook handlers I wanted to raise a concern of implicitness and complexity. Prior there was already some mixed handling in regards to lifecycle processing and schemas (as a higher level abstraction on top of those). That said the later are certainly useful as a common pattern which provide not just a convenient shortcut but even more strong-type safety for requests and responses using
Eden
. In general they work fine.Though based on the documentation and usage via code it is not directly transparent what their relation is. In general events, macros and schemas are all applied as hooks throughout the lifecycle of an incoming connection. Each of them can be defined at different levels as:
onAfterHandle(...)
& Co.,.schema(...)
)scope
d /groupe
dEspecially on the local layer there can be now an 'overloading'as macros can be defined. Therefore I wanted to suggest the following for better readability and composability:
schema: {...}
for the local hooks, scoped guards etc. even though it is not supported. While not many might take a look at those it's certainly helpful to have valid ones set, preferably matching the ones in other documented places.afterHandle
as well as schema validations such asbody
. Each of them is part of the lifecycle/hook stack but they are different abstractions which are not equally essential as the baseline (even more for custom macros). By having an envelope this can be easier communicated while also making it easier to share respective definitions between scoped and global handlers.Current:
After:
schema
interface (which is used for the.schema(...)
global handler as well as theschema
field of the local route hook) so that there is a clear separation forrequest
andresponse
. This wayresponse
doesn't feel like an afterthought being attached toquery
,params
orbody
but is at a similar level as there is arequest
envelope for those fields. Later on there might even be additional validation schemas for outgoingcookie
values with a familiar structure. Or there can be additionaldetail
for better documentation of a response for a specific status code.Current:
After:
Doing those will make the usage more verbose but in return should prevent confusion as its easier to reason how something gets set. Finally on the internal side it can help to share interfaces while avoiding collisions. In return the additional nesting layer might be convoluted for simple definitions its about balancing.
What do you think?
Beta Was this translation helpful? Give feedback.
All reactions