hoodiehq / hoodie

:dog: The Offline First JavaScript Backend
Apache License 2.0
4.4k stars 462 forks source link

Hoodie Client + React Native #732

Open alterx opened 7 years ago

alterx commented 7 years ago

First of all, thank you all for such an amazing tool 💯

I'm building an app that I want to be resilient when dealing with adverse network conditions and I think Hoodie is the right choice so I've been trying to integrate the Hoodie client with React Native but I keep getting these 415 Unsupported Media Type errors. One possible fix (that works for me) is to use application/json as a Content-Type in @hoodie/account-client/utils/request.js but I'm not familiar enough with Hoodie to tell if we can do that without breaking the client for other platforms (web).

Is there any reason why @hoodie/account-client/utils/request.js uses application/vnd.api+json instead of application/json as a Content-Type ?

Thanks

gr2m commented 7 years ago

Hey @alterx, thanks for the kind words! Cool that you give Hoodie a try with a React Native app, there were others expressing interest in that combination, hope you can share your setup once you have it working, we are happy to help!

We use application/vnd.api+json as content-type as the client server API is implementing JSON API which requires this content type to be set. The full specification of the REST API that @hoodie/account-client is working against can be found at http://docs.accountjsonapi.apiary.io/#

I’ve no experience with React Native myself. Could you check if others successfully implemented JSON API with a React Native app? Maybe they found a workaround?

alterx commented 7 years ago

Oh, I see. Yeah, now it makes sense. Thanks for the quick response @gr2m

I think I just discovered the root cause of the issue, it looks like Android somehow adds a media type parameter to the Content-Type header (charset=utf-8) and according to http://jsonapi.org/format/ "Clients MUST send all JSON API data in request documents with the header Content-Type: application/vnd.api+json without any media type parameters.". This issue is not present in iOS. Once I find a proper fix will post it back here.

alterx commented 7 years ago

It looks like the issue goes deeper than I thought, probably into the native android code. There's and open issue in the react native repo https://github.com/facebook/react-native/issues/8237#issuecomment-295790510 and I've added some details.

For the time being the only solution seems to add something like this

      server.ext('onRequest', function (request, reply) {
        if (request.headers['content-type'] && request.headers['content-type'].indexOf('application/vnd.api+json') !== -1) {
          request.headers['content-type'] = 'application/vnd.api+json'
        }
        reply.continue()
      })

and spin off a custom hapi server that uses the rest of the @hoodie/server packages

gr2m commented 7 years ago

you can add a custom onRequest extension for your Hoodie app by creating hoodie/server/index.js and adding the code in there like this

module.exports = function (server, options, next) {
  server.ext('onRequest', function (request, reply) {
    if (request.headers['content-type'] && request.headers['content-type'].indexOf('application/vnd.api+json') !== -1) {
      request.headers['content-type'] = 'application/vnd.api+json'
    }
    reply.continue()
  })
}

But note that you only want the requests to be affected that start with /hoodie/account/api, all other requests should be unaffected.

If this is a known issue on Android OS level, I also wouldn’t mind to not fully comply to the JSON API specification and also accept application/json as content-type. We could make the change in @hoodie/account-server with a comment that references this issue here. Not sure this will all work out but we can explore it

alterx commented 7 years ago

For the time being I'll just stick with the custom extension until I get a word about this being an Android issue. @gr2m, is there a preferred way to distribute this custom extension? Or should I just add it to my hoodie node_modules folder?

gr2m commented 7 years ago

we are very close to enabling 3rd-party-plugins, you can follow the status at https://github.com/hoodiehq/camp/issues/104.

Until then, you can put the extension in your own app, not in the node_modules folder, but into hoodie/server/index.js as I mentioned above. Once we have 3rd party plugins, you can publish the extension as its own 3rd party plugin to npm without doing any changes to the code :)

alterx commented 7 years ago

Perfect, I'll do that then and will keep an eye on the third-party plugins.

Should we keep this issue open until there's an "official" way of integrating RN and Hoodie or figure out if this truly is an Android issue?

gr2m commented 7 years ago

yeah I’d keep that issue open for others that look into React Native & Hoodie, thanks :)

gr2m commented 7 years ago

Hey @alterx, just wanted to let you know that we (silently) shipped 3rd party plugins: http://docs.hood.ie/en/latest/guides/plugins.html

Would love to hear what you came up with. I’d love to look into Hoodie/react (native) myself soon

alterx commented 7 years ago

So cool, @gr2m ! It's actually pretty straightforward.

This also means that I can start working on https://github.com/hoodiehq/faq/issues/142 😄

gr2m commented 7 years ago

Nice! Looking forward to learn more :)

alterx commented 7 years ago

Here's my first attempt, @gr2m : https://www.npmjs.com/package/hoodie-plugin-react-native-server

Let me know what you think.