This is intended as a very low-friction means of turning structured yaml into a GraphQL service. If you have a directory containing structured yaml, I want it to be as simple as this:
- create a schema file formalizing your data structure
- drop in a Dockerfile
- build a container and run
See the example for a quick start.
I deal with infrastructure as code a lot, and have found myself writing boilerplate to consume a repo full of yaml for various purposes. It makes more sense to me to expose the whole repo as a GraphQL service, and pull out what I need using a query (say with a terraform data provider). This seems like something that could be useful in other contexts.
Suppose you have this schema:
type A {
b: B!
}
type B {
c: C!
}
type C {
id: Int!
name: String!
tags: [String!]
}
type Query {
a: A!
}
schema {
query: Query
}
And these files:
---
# index.yml
a:
b:
c:
id: 14
---
# a/b.yml
c:
name: Biggy
tags:
- Boss
---
# a/b/c/index.yml
tags:
- Big Shot
- Winner
---
# a/b/c/tags.yml
- Inspiration
- Mentor
...or any other ridiculous combination you can think of.
Then all the data should get appropriately merged so you can query:
{
a {
b {
c {
id
name
tags
}
}
}
}
to get
{
"data": {
"a": {
"b": {
"c": {
"id": 14,
"name": "Biggy",
"tags": [
"Boss",
"Big Shot",
"Winner",
"Inspiration",
"Mentor"
]
}
}
}
}
}
The yaml file use case threw up a common pattern where there's an array of objects represented by a directory of yaml files, or a mapping of objects, where each filename or key respectively logically represents a unique identifier field within each object.
E.g.
teams
├── backend.yml
├── frontend.yml
├── qa.yml
└── sre.yml
If you want the filename mapped to a field in your GraphQL type, you can use the @confql(arrayIdentifier: true)
directive. E.g.
type User {
name: String!
email: String!
}
type Team {
name: String! @confql(arrayIdentifier: true)
members: [User!]!
}
type Query {
teams: [Team!]!
}
schema {
query: Query
}
Then, in the above case, the strings backend
, frontend
, qa
, sre
would get mapped to the name
field of each Team
in teams
.
This also works with directory names if you've broken your data up further, e.g.
teams
├── backend
│ ├── index.yml
│ └── members.yml
├── frontend.yml
├── qa.yml
└── sre.yml
Similarly, you can get the same effect from a mapping:
---
# teams.yml
backend:
members:
- name: Bill
email: [email protected]
frontend:
members:
- name: Will
email: [email protected]
# etc.
At its heart, this is a procedural macro which takes a path to a schema file, and at compile-time generates a juniper server with all necessary functionality to resolve data from the filesystem adhering to the given schema. It is draws much inspiration from, and is much more basic than juniper-from-schema.