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.