-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@hoodie/api #117
Comments
I like the idea of a server API. We’ve had something like this in the past and punted on it in favour for using raw PouchDB as the Server client API for the current iteration, but I always envisioned that we bring back a higher level API on the server.
I don’t see at all how this makes For the moment, I think |
they are not part of |
I foresee that the API will be used outside of the server, e.g. in a |
continuing a discussion from the IRC, a modified diagram might look something like
idea being that application-specific plugins could use this setup to modify the server db. i generally agree that it's beginning to look like a hurd of cats/dogs/chickens/bears/whoknowswhat, but this really is exactly what i was thinking the existing perhaps the
i dunno, it's really a tough call, kind a "can't please all the people all the time" cohesion/decoupling quandry. keeping that original "hey i made a webapp in an hour!" vibe is probably as good a guiding light as any to follow in these code design considerations. |
I think your use case is already covered by the original idea. You’ll be able to do something like this in plugins server.app.hoodie.store.open('mydb')
.then((db) => {
// do something with the database
}) Or am I missing what you need? Maybe describe it on a higher level? |
yes, it definitely is: the first high-level block diagram in my previous comment is indeed an extension of the the imagined architecture of the original idea. in the second block diagram, the low-level api details or dreamcode might look something like const PouchDB = require('pouchdb')
PouchDB.plugin(require('pouchdb-hoodie-api')(
server.some.path\....
))
const dbApi = (new PouchDB('mydb')).hoodieApi();
// do things (open, create, etc.) and the thing that having to write a few lines of boilerplate in plugins would buy is the simpler high-level diagram and possible associated code-design benefits: there can be fairly tight cohesion if the hoodie/hapi or, if i've grossly misread the purpose of const dbApi = require('@hoodie/api')(
server.some.path\...
) and the previous paragraph still applies with a few name changes. the overall message was, "yes, this does appear to do exactly what i was asking about in IRC re. i dunno if the "inversion of config" (somewhat like IoC) design of the second block diagram and dreamcode snippets above is the best way to address @janl 's comment. it is a semi-definite point of departure for discussion. a final, and perhaps the most important, note that i can bring to the table: unless the only use-case is to have databases that are entirely plugin, cli, etc. dependent, it might be more instructive to use more definite names than in short, adding the context of an end-to-end use scenario to some of examples that currently only use |
An issue like this should go through an RFC process which we discuss at #85 but did not setup yet, so this issue must do :)
🤔 Some background information for context
Hoodie always had an API in the client, that’s how it all started about 5 years ago: we dreamed up the nices client API for common web applications and made it work backwards. Today’s Hoodie Client API is only slightly different from what we came up back then.
JavaScript APIs on the server are new, we did not plan them, they grew organically. Hoodie’s core modules are Account & Store, both have a client and a server component which work together. The server part is using hapi to define its routes and define hooks around request life cycles. The logic to user account documents, user databases, security settings etc have all been part of @hoodie/account-server and @hoodie/store-server. Once we identified the patterns we moved the logic out into its own repositories: @hoodie/account-server-api and @hoodie/store-server-api. We are also working on the task module which will be split up in a similar way.
So things grew organically, and Hoodie’s architecture (for the server side) looks currently like this:
Because of that, accessing the account server api is possible at
server.plugins.account.api
.But what would make much more sense is
server.app.hoodie.account
. Theserver.app
comes from hapi, it’s meant to be used for app-specific state.In order to make that possible, I suggest a new architecture
❓ The Motivation
For one, it makes sense to have an API on the server just like we have it on the client. The difference is that while the Hoodie Client API is scoped to a signed in user, the Hoodie Server API would be from the admin perspective, allowing to manage user accounts, databases, etc.
The benefit for plugin developers is two fold:
server.app.hoodie
is simpler to explain and understand. We could have a central place where we document Hoodie’s Server API just like we do with the client APIThe second point is important. CouchDB’s
/_changes
feed is a great API that can be used as an event bus for distributed systems. Plugins could run in own processes, even on different machines, and could be scaled up and down independently. When they crash, they won’t take down the entire server, and the other way around. I’ve created such architectures several times in the past, so did many others – and we want to make it a first class citizen at Hoodie.Last but not least, having the Hoodie Server API which talks directly to the CouchDB (or PouchDB, what ever is configured on the Server) can even be used by itself in things like a Hoodie CLI tool, e.g. think
$ hoodie console
. I’m sure people will come up with many interesting use cases beyond what we can imagine today.Because of the prospect of
@hoodie/api
being used outside of a server, I prefer@hoodie/api
over@hoodie/server-api
and e.g.@hoodie/account-api
over@hoodie/account-server-api
. We need to clarify the naming in our documentation to make sure people understand the difference between@hoodie/client
and@hoodie/api
, but after giving this lots of thoughts, it makes perfectly sense.@hoodie/api
is talking to the database directly using PouchDB, data is directly read from / written to the database. All security checks must be done before calling the respective APIs.@hoodie/client
is not talking directly to the PouchDB where all of users’s data and all user accounts are store, instead it is talking through@hoodie/server
which defines routes. Within its route handlers all security checks like session checks are taking place.Here’s a diagram
📋 The plan ™️
@hoodie/api
. Add@hoodie/store-server-api
and@hoodie/account-server-api
as dependencies. This module should work similar to how@hoodie/client
works today. It should accept aPouchDB
constructor and other options and return an API for.account
and.store
. It should also implement a.plugin
method like@hoodie/client
’shoodie.plugin
method.hoodie-account-server-api
repository tohoodie-account-api
@hoodie/account-server-api
in package.json to@hoodie/account-api
@hoodie/account-api
to npm with the next breaking version after the current version of@hoodie/account-server-api
hoodie-store-server-api
repository tohoodie-store-api
@hoodie/store-server-api
in package.json to@hoodie/store-api
@hoodie/store-api
to npm with the next breaking version after the current version of@hoodie/store-server-api
@hoodie/account-server
to@hoodie/account-routes
. Remove the dependency on@hoodie/account-server-api
. Adapt the implementation to consume the API set onserver.app.hoodie.account
instead of instantiating its own API required from@hoodie/account-server-api
. Then manually release@hoodie/account-routes
to npm with next breaking version after the current version of@hoodie/account-server
. Create a git tag and a release as ifsemantic-release
did it to keep the changelog of past releases.@hoodie/store-server
to@hoodie/store-routes
. Remove the dependency on@hoodie/store-server-api
. Adapt the implementation to consume the API set onserver.app.hoodie.store
instead of instantiating its own API required from@hoodie/store-server-api
. Then manually release@hoodie/store-routes
to npm with next breaking version after the current version of@hoodie/store-server
. Create a git tag and a release as ifsemantic-release
did it to keep the changelog of past releases.@hoodie/api
as dependency to@hoodie/server
and instantiate it with it. All the cross-initialisation between@hoodie/account-api
and@hoodie/store-api
(e.g. create a user database when an account gets created) should still live in@hoodie/server
, not in@hoodie/api
. Setserver.app.hoodie
to the@hoodie/api
instance. Remove@hoodie/account-server
&@hoodie/store-server
from dependencies and add@hoodie/account-routes
&@hoodie/store-routes
instead. Release a new breaking version@hoodie/server
dependency inhoodie
. In the same PR, update documentation in thedocs/
folder.The Hoodie Client API
should be renamed toClient
andThe Hoodie Server API
should be renamed toAPI
. We should also addRoutes
but we can leave that out for now or create a placeholder page which has a link to an issue where we track the progress on it. Release a new breaking version.@hoodie/account-server
on npm@hoodie/account-server-api
on npm@hoodie/account-store
on npm@hoodie/account-store-api
on npm💭🤔💡💬 Discuss!
This was all in my head for way too long. Feels good to get it out there. I know it’s a lot to digest. Let me know what you think :)
🍬🍩 Bonus ✨
As mentioned above, Hoodie’s server API grew organically, it was not thought through and discussed endlessly like we did with Hoodie Client. Now if we make
@hoodie/api
a first class citizen, we should probably do that now.For example, instead of having an API like
hoodie.account.accounts.find()
andhoodie.account.account(id).tokens.add()
we probably rather wanthoodie.account.find()
andhoodie.account(id).tokens.add()
.Time for some dreamcoding :)
Last input I’d like to share is that
@hoodie/api
could have a very similar API as@hoodie/admin-client
– ideally it would even be the same! The difference would be that@hoodie/api
would talk directly to PouchDB while@hoodie/admin-client
would talk to routes defined by@hoodie/admin-routes
, so it would need to know the admin credentials for the respective Hoodie app.The text was updated successfully, but these errors were encountered: