As I developed a response to this question, I realized it might be something good to share as it’s own thing.
I think it would be cool to get feedback from others on my notes below, and also see what else others have to add.
Cheers!
Use a script to version control everything
You can uploaded a GraphQL schema and bootstrap Indexes, Functions, and Roles at the same time.
Here is an example script to upload schema and run other queries.
Tip for uploading a schema from code: Do NOT use multipart/form-data!
I’ve also published a package that can be used to break a schema into multiple files and use type extensions.
I have not settled on the best way to do this in a modular way, or best way for error handling across all bootstrapping queries. Though I really like keeping the UDFs that are called directly as GraphQL resolvers in a separate file.
Other good practices for this should be considered, but of course are not unique to GraphQL implementation:
- script idempotency (e.g. use
CreateOrUpdateFunction
) - error handling
- etc.
Create Wrapper UDFs for GraphQL resolvers.
While using Fauna’s native GraphQL with custom resolvers, I’ve discovered the following:
- There are a lot of UDFs that are not GraphQL resolvers. I want to keep the separated in code and dashboard.
- GraphQL UDF signatures (input and returns) are often different than what is good for reusable UDFs.
- It is helpful to compose UDFs that return a Set, so that you can
Union
orIntersection
them. - Some resolvers trigger a whole bunch of logic run in UDFs. I want good reusable UDFs.
This is why I recommend creating a UDF that makes sense in FQL land, then making a separate one for the GraphQL resolver.
I’ve not settled on a naming convention, but I am liking adding gql_
to the beginning for now.
Different inputs
GraphQL wants you to give it IDs. FQL wants the whole Ref.
Resolver UDF creates the Ref given an ID and calls the other UDF.
{
name: "somethingWithUser",
body: Query(
Lambda("userRef", /*...*/)
)
}
{
name: "gql_somethingWithUser",
body: Query(
Lambda("userId", Call(
Function("somethingWithUser"),
Ref(Collection("User"), Var("userId"))
))
)
}
Different outputs
GraphQL wants the results to be Documents, not Refs. But to make UDFs reusable often means you just want to work with Refs, or you want to return an index with multiple values.
Resolver UDF Map
s results to Get
the documents.
{
name: "gql_getSomeThings",
body: Query(
Lambda([], Let(
{ things: Call(Function("getSomeThings")) },
Lambda("ref", Get(Var("ref")))
))
)
}