haskell-servant / servant

Servat is a Haskell DSL for describing, serving, querying, mocking, documenting web applications and more!
https://docs.servant.dev/
1.83k stars 414 forks source link

Is it possible to make servant-client also work with ghcjs #940

Closed tysonzero closed 5 years ago

tysonzero commented 6 years ago

I'm currently getting a uncaught exception in Haskell thread: ReferenceError: h$hsnet_getaddrinfo is not defined error when using servant-client-0.11.

Some research seems to indicate that servant-client doesn't work in the browser. Is there any chance it can be made to work in the browser so that I can use the same client functions when compiling with both ghc and ghcjs, and if not would it be possible for the error message to be more clear, like servant-client not supported in browser, please use servant-client-ghcjs.

phadej commented 6 years ago

See servant-client-ghcjs package in the repository (not yet published)

tysonzero commented 6 years ago

Yeah I know about servant-client-ghcjs, I mentioned it in the question, just wanted to see if I could use a single package both in the browser (ghcjs) and on the server (ghc). It also would be nice to use a package that's on hackage / stackage / nixpkgs.

alpmestan commented 6 years ago

A single package would be the simplest for users, but I think it's a bit of a nightmare for the implementors (haven't worked on servant-client-ghcjs myself, but I've seen others struggle with this very idea, because you then have to stuff everything under common types/functions, which is not necessarily desirable). It should definitely be on hckage though, yes, but it's not well tested and doesn't get a lot of love. I think we don't even check it in CI yet because of how complicated it is to have CI run over it while staying in the free tier of travis, IIRC. So yeah, this package really needs someone or several someones who care about getting servant-client to work nicely with ghcjs, I think. @FPtje is I think one of the few persons who've worked on this, in case you want to get in touch and discuss the current state of things etc.

FPtje commented 6 years ago

servant-client-ghcjs works, but there are some development challenges. For one, there are tests, but they're in a separate repository (https://github.com/FPtje/servant-client-ghcjs-test) since the tests involve both a server and a client application. Running a test is done by starting the test server, going to the page in a browser and checking the output of the console.

It should be possible to test using nodeJS, which should make it easier to automate the test, though I haven't looked at that yet.

The biggest practical issue we have with servant-client-ghcjs is that the sending and receiving of binary data isn't supported, though that's fixed in #938.

Other than that servant-client-ghcjs has some serious things going for it. We can re-use the API specification and even the client functions in servers, regular clients and browser clients. That and it abstracts the browser's XHR mechanism, which is super convenient.

tysonzero commented 6 years ago

@FPtje Ah ok that all makes sense, nice work!

So if you can use servant-client-ghcjs in servers and regular-clients, I assume that means it works with ghc. At which point what is the difference between it and servant-client? Is it something to do with the mechanism by which each does api requests, sockets vs http requests or similar, in which case would a name change be appropriate?

FPtje commented 6 years ago

No, that's not what I mean. I mean that we can define client functions in haskell files that are compiled by both ghc and ghcjs. On ghc we can call those client functions using servant-client, on ghcjs we can call them using servant-client-ghcjs. servant-client doesn't compile on ghcjs, and servant-client-ghcjs doesn't compile on ghc. Sorry if that was unclear.

servant-client-ghcjs very specifically uses Javascript's Xhr mechanism. servant-client (through a library) sends the http requests using system sockets.

alpmestan commented 6 years ago

@tysonzero Just to clarify, there are 3 packages at play here:

You can derive client functions "polymorphic in the backend" using servant-client-core and I think this is what @FPtje is alluding to in the comment above. Or you can conditionally import one backend or the other depending on the compiler of the current module, perhaps. Anyway, you probably get the idea. There's one backend-agnostic package, 2 distinct backends.

tysonzero commented 6 years ago

Thanks for the elaboration, that makes sense. On a side note is it true that servant-client does work for ghcjs as long as you use it with node / something with access to sockets?

arianvp commented 6 years ago

If ghcjs has the correct stubs for the network library then the answer is yes. but I'm not sure if it does.

phadej commented 5 years ago

There is servant-client-ghcjs