Vulcan in a Nutshell
The best way to understand how Vulcan works is to consider its three main aspects: the role of the schema, how Vulcan reads data, and how Vulcan writes data.
Overviewβ
The Schemaβ
At its core, a Vulcan schema is just a JavaScript object containing a list of fields such as name
, _id
, createdAt
, description
, etc. describing a type of document (a movie, a post, a photo, a review, and so on).
The schema is what defines how a Collection (you might also be more familiar with the equivalent term βmodelβ) behaves, and it fulfills many important functions:
- It's used to generate your GraphQL schema, which in turn controls your app's GraphQL API.
- It's used to control permissions.
- It's used to generate forms.
Reading Data (Queries)β
Reading data basically means getting data from your database all the way to the user's browser.
Let's assume we want to take a list of movies currently stored in our database and display it inside a Movies.jsx
component. Here's a quick overview of the entire data lifecycle:
Componentβ
The Movies.jsx
component expects a results
prop. But how will it receive it?
Hook/Higher-Order Componentβ
In order to receive that prop, the component will need to be wrapped with the withMulti
higher-order component. You just need to specify the appropriate Collection, and optionally also specify a fragment to define which document fields to load.
Alternatively, you can do the same thing through the useMulti
hook.
GraphQL Queryβ
The withMulti
HoC (or useMulti
hook) will trigger an Apollo query to the app's GraphQL endpoint using the movies
query resolver.
This is the same kind of query you would write manually in any regular GraphQL app, but in this case the query is auto-generated by the HoC or hook.
Resolverβ
The query triggers a resolver function. The job of that function is to take the query arguments and output the corresponding data in return, after making sure the current user is authorized to access said data.
Connectorβ
Finally, the resolver queries the database to retrieve the data. This is done through a connector, a function that translates a generic find
request into instructions specific to the current database.
Writing Data (Mutations)β
Now let's consider the opposite operation: writing data, such as editing a movie's description using a form.
Componentβ
First, you should know that the movie update form component can be automatically generated from your schema, meaning you don't actually need to code it or worry about hooking it up to your GraphQL API.
Hook/Higher-Order Componentβ
That form is wrapped with the withUpdate
HoC.
GraphQL Queryβ
The HoC in turn will call the updateMovie
mutation on the server (which again can be automatically generated from default mutations).
Resolverβ
On the server, the update
resolver takes in the mutation's arguments (an object indicating which document to update, as well as the payload containing the actual changes) and after some permission checks to make sure the current user is authorized to perform the mutation passes them on to the mutator.
Mutatorβ
updateMovie
will then call a boilerplate mutator which will perform validation based on your schema, and finally call the database connector.
Connectorβ
The database connector then modifies the document inside your database.