Queries
When using Vulcan’s default resolvers, two types of queries are automatically generated for every collection: the single query (which returns a single document) and the multi query (which returns a list of documents).
A set of default query resolvers is generated on the server to power these queries; and a set of client-side higher-order components and hooks is provided to make working with those queries easier.
API
All Vulcan queries follow the single argument pattern. In other words, they take a single input argument that encapsulates all of the query’s variables; and they return a single output object that contains all the query data.
Single Query
Here is an example single query definition for a Movie type:
1 | movie(input: SingleMovieInput): SingleMovieOutput |
And here’s an example query:
1 | query myMovie { |
Multi Query
Here is an example multi query definition for a Movie type:
1 | movies(input: MultiMovieInput): MultiMovieOutput |
And here’s an example query:
1 | query myMovies { |
Input Argument
Both single and multi queries take the same arguments (with the exception of limit, which is only available for the multi query). The only difference is that in the case of the single query, if the filter argument selects more than one document only the first document of the set will be returned.
The input takes the following properties:
filter: the object that lets you select the specific documents to return.sort: how to order the results.limit: how many results to return.offset: how many results to skip.search: a shortcut for searching across all searchable fields at once._id: a shortcut for selecting a specific document by_id.enableCache: whether to enable caching for this queryallowNull: whether to returnnullinstead of throwing an error when no document is found.
Here is an example input type for the Movie type:
1 | input SingleMovieInput { |
You can learn more about these arguments in the filtering section.
Client
Vulcan also offers built-in client-side helpers that will generate the right GraphQL query for you.
Hooks
useSingle
1 | const { result, loading, error, networkStatus, refetch } = useSingle2({ |
You will find the document available as the result property of the hook’s return object. Note that under the hood useSingle2 and useMulti2 use Apollo’s useQuery, and all of that hook’s return values are also available in useSingle2 and useMulti2.
useMulti2
Usage:
1 | const { results, loading, error, networkStatus, refetch } = useMulti2({ |
Options:
collection:collectionName:fragment:fragmentName:
Returned properties:
-loading: Bool – indicates whether the query is loading.
-loadingInitial: Bool – indicates whether this is the initial load.
-loadingMore: Bool - indicates whether the query is loading additional data.
-results: Array – the results returned by the query.
-totalCount: Int – the total non-paginated count for the documents matching the query.
-refetch: Function – a function that lets you re-run the query.
-networkStatus: Int – the Apollo Client network status.
-error: Error – the Apollo Client error.
-count: Int – the count of paginated documents matching the query.
-loadMore: Function – a function to load more documents.
-loadMoreInc: Function – a function to load more documents incrementally.
-fragmentName: String – the name of the fragment used to load the data.
-fragment: Object – the fragment used to load the data.
-data: Object – the raw Apollo Client result object.
1 | import React from 'react'; |
Higher-Order Components
Note: HoCs are now deprecated in favor of hooks
To make working with Apollo easier, Vulcan provides you with a set of higher-order components (HoCs).
An HoC is simply a function you can call on a React component to give it additional props. Think of it as a mechanic’s assistant following along with a little toolbox, ready to hand over a screwdriver or socket wrench at the appropriate time.
withMulti
The withMulti HoC is used to display lists of documents. It takes the following options:
Options
collection: the collection on which to look for thelistresolver.collectionName: alternatively, you can also pass the collection name as a string.fragmentorfragmentName: the fragment to use. If you passfragmentNameinstead offragment, the name you passed will be used to look up a fragment registered withregisterFragment.input: an optionalinputobject used to filter the data received (see filtering section). This argument can also be passed dynamically as a prop (see below).
For example:
1 | const listOptions = { |
Accepted Props
The resulting wrapped component also accepts a dynamic input object as a prop.
This can be useful when you want your data to change based on some user action such as selecting filtering options in a dropdown, changing sorting order, etc.
The dynamic input will always take priority over any “static” input defined in the HoC’s initial options.
Passed-on Props
The HoC then passes on the following props to the wrapped component:
loading:truewhile the data is loading.results: the loaded array of documents.totalCount: the total count of results.count: the number of current results (i.e.results.length).refetch: a function that can be called to trigger a query refetch.loadMore: a function that can be called to load more data.
withSingle
The withSingle HoC displays a single document.
Options & Props
It takes the same options and props as withMulti, except that its input can have an _id property and doesn’t support the limit property.
Passed-on Props
This HoC then passes on the following child prop:
loading:truewhile the data is loading.document: the loaded document.refetch: a function that can be called to trigger a query refetch.
Server
Resolvers
Vulcan provides a set of default List, Single and Total resolvers you can use to save time by calling getDefaultResolvers(collectionName):
1 | import { |
The options object can have the following properties:
typeName(String): the resolver’s type name (required).cacheMaxAge(Number): a custom cache age (in seconds) for the resolvers.
To learn more about what exactly the default resolvers do, you can find their code here.
Custom Resolvers
In some cases, you will want to go beyond the three default resolvers. For example, you might want to create a resolver that returns a single random post, or the current user. You can do so by using addGraphQLResolvers and addGraphQLQuery:
1 | import { addGraphQLResolvers, addGraphQLQuery } from 'meteor/vulcan:core'; |
addGraphQLResolvers adds the actual resolver function, while addGraphQLQuery adds the corresponding query type (if your new resolver is not mentioned in your GraphQL schema, you won’t be able to query it).
Learn more about resolvers in the Apollo documentation.