apicollective/apibuilder-generator

http4s does not handle 401

Closed this issue · 4 comments

@gheine @fiadliel @amarrella

If I define 401 response type like this

      "responses": {
        "200": {
          "type": "account"
        },
        "400": {
          "type": "unit"
        },
        "401": {
          "type": "unit"
        }
      }

The resulting generated code ...

case PostSignInResponse.HTTP401(headers) => Unauthorized().map(_.putHeaders(headers: _*))

... fails to compile:

[error] ...............: overloaded method value apply with alternatives:
[error]   [A](authenticate: org.http4s.headers.WWW-Authenticate, body: A, headers: 
org.http4s.Header*)(implicit F: cats.Monad[F], implicit w: 
org.http4s.EntityEncoder[F,A])F[org.http4s.Response[F]] <and>
[error]   (authenticate: org.http4s.headers.WWW-Authenticate,headers: org.http4s.Header*)(implicit F: cats.Applicative[F])F[org.http4s.Response[F]] <and>
[error]   (challenge: org.http4s.Challenge,challenges: org.http4s.Challenge*)(implicit F: cats.Applicative[F])F[org.http4s.Response[F]]
[error]  cannot be applied to ()
[error]         case PostSignInResponse.HTTP401(headers) => Unauthorized().map(_.putHeaders(headers: _*))
[error]                                                     ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 19 s, completed Mar 14, 2018 4:27:19 PM

That's because Unauthorized needs WWW-Authenticate header.

Below would compile, but I'm not sure about "Bearer" and "Organization".

case PostSignInResponse.HTTP401(headers) => Unauthorized(org.http4s.headers.`WWW-Authenticate`(org.http4s.Challenge("Bearer", "Organization"))).map(_.putHeaders(headers: _*))

My first hunch: the apibuilder format doesn't provide enough information to make a 401 actually work. Can a 401 work correctly for any generated server code target?

I'm guessing that most frameworks do not enforce WWW-Authenticate for 401 (although they should) like http4s does

You can build a Response[F] value manually rather than with these constructors if necessary. See https://github.com/http4s/http4s/blob/3dda6969adc46fc887da178b5a0976fca9d26c2d/dsl/src/main/scala/org/http4s/dsl/impl/ResponseGenerator.scala#L78 for what the underlying code looks like.

Yeah, we need to fix the HTTP401 response to take a authenticate: WWW-Authenticate in addtion to the headers. I might be able to look into this tomorrow.