armeria icon indicating copy to clipboard operation
armeria copied to clipboard

Support coroutines in `HttpService`.

Open Dogacel opened this issue 1 year ago • 0 comments

Similar to

  • #4669
  • #4725

We should have HttpService based on coroutines. Currently, only way to implement a suspend http service is using AnnotatedService. In some scenarios, users might want to use the HttpService or AbstractHttpService, which in my opinion has more granularly defined signatures which seem less like magic.

Sample proposed implementation 1 (inheritance)

abstract class CoroutineHttpService : HttpService {
    final override fun serve(ctx: ServiceRequestContext, req: HttpRequest): HttpResponse {
        val future = CoroutineScope(ctx.asCoroutineContext()).future {
            serveAsync(ctx, req)
        }

        return HttpResponse.of(future)
    }

    abstract suspend fun serveAsync(ctx: ServiceRequestContext, req: HttpRequest): HttpResponse
}

Sample proposed implementation 2 (composition)

interface CoroutineHttpService {
    fun serve(ctx: ServiceRequestContext, req: HttpRequest): HttpResponse
}

fun CoroutineHttpService.asHttpService(): HttpService {
    return HttpService { ctx, req ->
        HttpResponse.of(CoroutineScope(ctx.asCoroutineContext()).future {
            serve(ctx, req)
        })
    }
}

Ditto for AbstractHttpService.

Inheritance

Pros:

  • Drop-in replacement to HttpService because it inherits.

Cons:

  • Function name needs to be different such as serveAsync or coServe.
  • Needs to be an abstract class to prevent overriding serve.

Composition

Pros:

  • Method signatures are the same
  • Interface, similar to HttpService.

Cons:

  • Need to use .asHttpService() method to convert to an HttpService

Also need to check if we lose any valuable method if we don't inherit HttpService.

Dogacel avatar Feb 06 '24 03:02 Dogacel