Closed PawelJ-PL closed 5 years ago
There is an example of similar solution from Haskell Servant:
module Http.TestLink where
import Servant
import Universum
import Servant.Swagger.UI (SwaggerSchemaUI)
type NamesApi
= "v1" :> "test" :> Capture "id" Text :> "names" :> QueryFlag "testFlag" :> QueryParam "authors" Text :> ReqBody '[ JSON] Text :> Post '[ JSON] Text
type TestPut = "put" :> Put '[ PlainText] Text
type ReleaseInt = "release" :> Capture "myId" Int :> Post '[ PlainText] Text
type TestApi = TestPut :<|> ReleaseInt
type MyApi = NamesApi :<|> TestApi
type DocumentedApis = MyApi
type ApplicationApi = SwaggerSchemaUI "swagger" "swagger.json" :<|> DocumentedApis
linkTo id flag autor = linkURI $ safeLink (Proxy :: Proxy ApplicationApi) (Proxy :: Proxy NamesApi) id flag autor
linkTo "ttt" True Nothing
-- result -> v1/test/ttt/names?testFlag
linkTo "ttt" True (Just "testUser")
-- result -> v1/test/ttt/names?testFlag&authors=testUser
There's one problem here; the servant types capture more information than tapir does - that is, it's encoded in the type which parameter comes from the query, which from the path and which from the body (at least as far as I understand it). So they have the possibility of extracting the path-type only and generating a link.
With tapir, that's not possible - looking at the type of an endpoint's input, we don't know which values belong to the path, which to the query etc.
What would be possible, though, is defining a method which, given the input values, would "render the request" - that is return the path, query, headers and body.
This, in fact, would be quite close to interpreting an endpoint as a sttp request. Maybe that would work for you?
I think it should be ok. In my case I'm constructing sttp Uri
instance from extracted path
According to discussion on Gitter, it would be nice to have methods for extracting path from endpoint. My proposal:
For endpoint:
1)
def renderPath(): String = ???
example call:myEndpoint.renderPath()
should return:aaa/bbb/:s1:/ccc/:s2:
2) I'm not sure how easy it will be to achieve because number and type of segments won't be fixed:
def renderPath(segments: (String, Int)): String = ???
example call:myEndpoint.renderPath(("XXX", 123))
should return:aaa/bbb/XXX/ccc/123
3) With:
def pathFragments(): Seq[PathFragment] = ???
example call:myEndpoint.pathFragments():
should return:Seq(PathFragment.Fixed("aaa"), PathFragment.Fixed("bbb"), PathFragment.Captured("s1"), PathFragment.Fixed("ccc"), PathFragment.Captured("s2"))
I'm not sure about third method. Maybe it could be improved.