-
Notifications
You must be signed in to change notification settings - Fork 51
Evaluate feasibility of a REST API #220
Comments
Further remarks on building with CouchDBConsider this architecture:
In this architecture, the user is always working with locally stored data. Should they lose connectivity, service is not degraded -- the CouchDB node simply stops receiving updates until connectivity is re-established, at which point updates resume. Likewise pending transactions can be saved in this way, as documents within the database which the Proxy only processes once connectivity is restored. With Relay in mind, which proactively updates components as they change in the datastore, it is possible to do this with CouchDB's _changes endpoint and filters. This is a preliminary description of an architecture for discussion. I am happy to expand the description in response to inquiry, and to walk through appropriate tooling and indexing practices. |
Great work, thanks! I think the idea of using CouchDB is really interesting, because indeed it saves us from having to maintain an HTTP API, as well as having to worry about persistence. In general, it will make sense to put things in some kind of database to handle persistence and querying, but also to get synchronization functionality. Eg. in the future it would be nice to be able to sync a mobile client with your desktop without having to process the whole thing from scratch. The advantage of couch over something sql-based is as you said, that we get the API for free - which is huge. What I would worry about is:
Overall though I still like the idea a lot. |
More generally about REST vs. GraphQL: REST is a lot easier to script, eg. with |
Thanks for the thorough and insightful write-up @garbados - this is a good start for further explorations. I'd like to keep the conversation focused on the actual Rest API part as a feasible alternative to the current GraphQL implementation. While there is a lot of interesting potential it also comes with a significant amount of operational and mental overhead. Also at this stage we don't need a indexing solution as we currently don't maintain one either. GraphQL itself doesn't maintain any indexes it purely wires DSL to resolvers which provide the data as per implementation (memory, postgres, network requests, etc.). For now we should avoid another materialisation layer which can introduce subtle issues with data consistency and availability. We should look into the needs and concerns brought up here wrt mobile clients in isolation as follow-up(s). What would be good as actionable outcome is to define a package which shows an implementation path that we can look at side-by-side. It should full-fill the following requirements:
Outlining this package and following up with an implementation should be possible in a day. |
Though I agree that we should start by looking at REST more in the abstract (so let's start with that), I also don't really see how the proxy could work without a backing database. It would require querying the registry for all projects and users stored in radicle-link on startup.. |
radicle-link operates on local data already, unless we see this becoming a bottleneck there is not much we would gain from storing the same data in another place for now. While it's reasonable to assume that the UX will benefit from local caching/indexing it's an orthogonal concern to this issue and as I said will be captured in a follow-up. How and what we want/can cache is a non-trivial question which needs proper investigation. |
Radicle REST APIIntroductionThis REST API is intended for consumption by the radicle-upstream user application, and thus presumes a one-user, one-device environment. Authentication has not been considered in this design as it is presumed that the only software able to access the API will be the application itself. In the future, we can add authentication capabilities to support modders that want to take advantage of the API to develop applications that interact with the Radicle network. For now that use case is not under consideration. Entities and EndpointsThe server will respond with response bodies of JSON. Query parameters can pass options on GET and DEL requests, while information formatted into the content-type The non-URL parameters of endpoints will be enumerated after a demo implementation. OrgAn organization, or Org, is an identity with associated users and associated projects. Users can create organizations and add other users to them, or create projects under the organization. Endpoints:
UserA user is an identity with associated projects and associated organizations. A user can create projects associated with themselves, or with any organizations that have granted them sufficient permissions. Endpoints:
ProjectA project is a code repository with associated collaboration artifacts. Endpoints:
CommitA commit is a specific revision of a code repository, and thus must be referred to with the ProjectId of its associated project.
BranchA branch is a revision tree within a code repository, and thus must be referred to with the ProjectId of its associated project.
ConsiderationsThis outline does not include code collaboration artifacts as those are not currently among the entities that the proxy supports. As I learn more about how we plan to represent these artifacts, I can incorporate them into the design. |
Ok, now about that demo implementation... |
Pursuant to #165, this issue explores the feasibility of a REST API by way of designing one. As an example:
Endpoints
Consider a set of HTTP endpoints scoped under the prefix
/api/v1
such that the path to the endpointidentities
is actually/api/v1/identities
. Object types referenced in this outline, such as "identities", refer to entities that are already described within the proxy as Rust structs.Entities
Endpoints deal with common, standardized entities, including:
The nature of these entities is already contained within the proxy. For example, here is the current characterization of an Identity:
All of these object definitions can be preserved in the transition to a REST API.
Query Parameters
Some endpoints list objects, such as listing projects or users. These lists can be scoped using common parameters, listed here:
mode
: A special index to use before other forms of scoping. As an example, considerGET projects?mode=popular
which would list projects indexed as "popular".start
: A key at which to begin the list. Used for pagination. For example:GET projects?start={id}
would list projects with IDs that sort after the given start ID.end
: A key at which to end the list. Used for pagination. For example:GET projects?end={id}
would list projects with IDs that sort before the given end ID.descending
: A boolean indicating whether to sort entries by their ID in an ascending (false, default) or descending (true) way.limit
: Integer indicating how many entries to return. Defaults to some reasonable number like 20, with an upper limit of 40.These options are inspired by those used in CouchDB views.
But this is rudimentary. Queries like finding projects registered by a given user or set of users would require constructing and maintaining indexes, which is beyond the scope of the API itself.
Indexing
GraphQL uses its own indexing engine, and moving away from it would mean we would need to choose or create our own. I highly recommend not creating an indexer and instead using a mature database with one of its own, such as PostgreSQL or CouchDB, because databases are very complicated and our time is limited.
If we used PostgreSQL, the REST API would essentially be an interface to highly controlled SQL queries, in order to prevent malformed or unintentional destructive database interactions. This is a relatively labor-intensive approach as our evolving data model would require frequent migrations, and any changes to the API required by the frontend would necessitate additional labor on the backend to write the appropriate query and return the appropriate information. This architecture -- of using a REST API as a mediator between client software and raw SQL -- is very common and best practices for it are well-established.
If we used CouchDB, which exposes its own REST API, the client could interact with CouchDB directly while the proxy simply monitors librad and the registry for relevant changes, which it pushes to the database which subsequently indexes them. This saves us the trouble of writing our own REST API and allows us to focus that labor on writing "views" AKA indexes, which the frontend can perform queries against. Queries are non-destructive so there is no danger of a malformed query destroying information. Furthermore, CouchDB implements advanced REST API features including etags which would otherwise be a considerable undertaking to develop ourselves.
NOTE: I mentioned an architecture using CouchDB during a meeting on March 11 that was very off-the-cuff and did not reflect a thoughtful architecture. It has no bearing on my suggested use of CouchDB here.
The text was updated successfully, but these errors were encountered: