nestia
nestia copied to clipboard
Support for Sse decorator
TypedRoute is not supporting Sse decorator from @nestjs/common, thus cannot use Nestia for SSE endpoints.
For example, for the code something like below,
// original decorator used
// @Sse('/path/to')
// Nestia decorator used
@TypedRoute.Get('/path/to')
async waitQueue(
@TypedQuery('id') queueId: string,
@Req() req: Request,
) {
const isCompleted = new Subject<void>();
return interval(3000).pipe(
takeUntil(isCompleted),
mergeMap(async () => {
// do stuffs
}),
);
}
if I use @TypedRoute.Get in place of @Sse, this endpoint will work as a normal GET method.
Could you please add @Sse decorator to TypedRoute, or is there any work around for SSE endpoints?
Do you have a good idea that how SDK should be generated?
If you have insight about it, can you write an example SDK code about that?
Honestly, neither do I know how Nestia generates sdk internally yet, nor am I skilled enough to contribute to your project. So, if you think this issue is not part of your primary goals, it's fine to close the issue.
Maybe I'll re-open this issue when I get better understanding to this project and become ready to contribute.
I mean just interface design goal of SDK what you want. Don't be burdened please.
Sure.
Would this be what you are expecting?
/**
* EventSource constructor:
* new(url: string | URL, eventSourceInitDict?: EventSourceInit): EventSource;
*
* interface EventSourceInit {
* withCredentials?: boolean;
* }
*/
interface EventSourceConnection {
url: string;
withCredentials?: boolean;
}
interface EventSourceListener {
/**
* EventSource event type
* pre-built types: 'message' | 'open' | 'error'
* but, can be any string
*/
type: string;
/**
* interface MessageEvent<T = any> extends Event {
* readonly data: T;
* }
*
* I'm not sure whether other properties are used.
*/
listener: (this: EventSource, event: MessageEvent) => any;
/**
* Indicates whether the EventSource connection should be closed after the event.
*
* For example, if true,
* the listner should be wrapped with eventSource.close().
*
* false, by default.
*/
close?: boolean;
}
API.path.to.methodName(connection: EventSourceConnection, ...listener: EventSourceListener[])
Just wrote it similar to how normal requests are handled. So, real use case might look like this.
API.path.to.methodName({
url: 'http://localhost:3000',
}, {
type: 'message',
listener: messageHandler,
}, {
type: 'error',
listener: errorHandler,
close: true,
}, {
type: 'complete',
listener: completeHandler,
close: true,
});
or maybe, the interface can return the EventSource instance, so that the user can add listeners.
*edit
const eventSource = API.path.to.methodName({ url: 'http://localhost:3000' })
eventSource.addEventListener('message', messageHandler);
eventSource.addEventListener('error', errorHandler);
eventSource.addEventListener('complete', completeHandler);
Hallo @samchon Thank you for the amazing work.
I've face the same struggle as described in this issue. I just ended up using https://github.com/Azure/fetch-event-source
instead of the sdk for this particular SSE endpoint.
Also thinking about how it can be integrate in nestia:
- If you don't mind integrating
fetch-event-source
as peer-dependency in nestia fetcher. Then the workflow will be like this.
a. nestjs enpoint has sse decorator ?
b. use SseFetcher ( leverage fetchEventSource from fetch-event-source-package )
c. wrap onmessage, onerror, onopen and onclose in Promise.
I've tested this approch with react-native client and it work fine.
- Another option would be really just to generate something like this for SSE marked endpoint. and repeat the option 2.c
const eventSource = new EventSource('/sse');
eventSource.onmessage = ({ data }) => {
console.log('New message', JSON.parse(data));
};
Again thank you for your amazing work.
Cheers.