---
tags: Dungeon Master
---
# Dungeon Master GraphQL Schema Notes
This is a list of GraphQL schema notes in order to accomplish the following userflows:
- Consultation comes in from our site → A logged in Cleric (verified their role) claims a Consultation and self-assigns → Consultation then becomes a Raid → They add Raiders to the Raid
- Raids can then be updated by the Cleric (and/or) Raid Party
- Logged in Raiders can see Raids they're on and a list of Raids by status
I started adding some of these but ran into some issues with needing to make sure our collections were connected together.
## Types
**General Notes:**
- Do we want to change the type for `id` to `ID` instead of `String` ? `ID` is a special string behind the scenes so would likely work the same way with the Mongo schema
### Enums
- Do we want to add the `enums` from `constants.js` into our typedefs? For example:
```graphql
enum PreferredContact {
DISCORD
EMAIL
TELEGRAM
}
```
- Doing this would allow for us to restrict input / output options at the GraphQL level instead of at the database level. This is useful but there are some limitations in formatting (such as no special characters)
- If we want to add these we could pull in all enums from `constant.js` into `typedefs.js`
### Date Scalar
- Do we want to add a Date scalar so that we can use custom Dates instead of strings?
- (example)
## Queries
These queries for grabbing individual data by `id` — right now the `id` is of type `String` but we could consider using the GraphQL type `ID`
**member**
```graphql
member(id: String): Member
```
**consultation**
```graphql
consultation(id: String): Consultation
```
**application**
```graphql
application(id: String): Application
```
**portfolio**
```graphql
portfolio(id: String): Portfolio
```
**comment**
```graphql
comment(id: String): Comment
```
We also may want to consider querying `Member` by `ethAddress` as well:
- If a Member logs in with MetaMask and we have their `ethAddress`, we could then use that to look up their Member info for role, current Raids, etc.
## Resolvers
- If we add the individual data queries (such as `member` `consultation` etc. we'd need to add the resolvers, such as:
```javascript
async raid(_parent, args, _context, _info) {
const { id } = args;
const response = await raid.findById(id);
return response;
},
```
7/22/21:
I've added the remaining resolvers.
**member(id)**
```javascript
async member(_parent, { id }, _context, _info) {
const response = await member.findById(id);
return response;
},
```
**memberByEthAddress(eth_address)**
```javascript
async memberByEthAddress(_parent, { eth_address }, _context, _info) {
const response = await member.findOne({ eth_address: eth_address });
return response;
},
```
**consultation(byid)**
```javascript
async consultation(_parent, { id }, _context, _info) {
const response = await consultation.findById(id);
return response;
},
```
**application(id)
**
```javascript
async application(_parent, { id }, _context, _info) {
const response = await application.findById(id);
return response;
},
```
**portfolio(id)**
```javascript
async portfolio(_parent, { id }, _context, _info) {
const response = await portfolio.findById(id);
return response;
},
```
**comment(id)**
```javascript
async comment(_parent, { id }, _context, _info) {
const response = await comment.findById(id);
return response;
},
```
---
### Nested/Chained Resolvers
NOTE: In our discussion on 7/22, we determined these likely aren't necessary.
- We'll want to create some additional nested/chained resolvers to make sure that our data collections are connected. For example, if we query RaidParty within Raid, we'd want to resolve the RaidParty first, which itself requires us to resolve Member.
Here are the connections we likely we need:
- `Consultation` and `Raid`
- `Application` and `Member`
- `Raid` and `RaidParty`
- `RaidParty` and `Member`
- `Comment` and `Raid`
We'd want to add these into `resolvers.js` at the same level as `Query` and `Mutation` so they can resolve themselves before being used in queries. This is different than the `raid` query.
```graphql
RaidParty: {
raid(parent) {
//filter db to find and return RaidParty connected to the connected raid -- something like
return raidparties.filter((raidparty) => raidparty.raid === parent.raid);
},
},
```
Resolver pattern for getting Raiders on a raid would be: Raid(id) -> connected RaidParty -> RaidParty Members. This would allow us to query something like:
```graphql
query Raid {
raid(id: "60e47c50c78dad9c697aa4f9") {
raid_name
status
raid_party {
members {
name
guild_class
}
}
}
}
```
This may not be needed depending on how the data is going into the database, but if we wanted to be safe we could add these resolvers. I may be overthinking this so definitely want to talk through it.
## Inputs
We could add `input` types for each of our queries, such as the `ConsultationInput`:
```graphql
input ConsultationInput {
id: ID
project_name: String!
contact_name: String!
contact_email: String!
contact_bio: String!
contact_discord: String
contact_telegram: String
preferred_contact: String!
project_type: String!
project_specs: String!
specs_link: String
project_desc: String!
services_req: [String!]!
desired_delivery: String
budget: String!
delivery_priorities: String!
additional_info: String!
submission_type: String!
consultation_hash: String
submission_date: String!
feedback: String
rating: Int
raid: RaidInput
}
```
- These can reference each other — for example, `raid` can reference a `RaidInput` once created
## Mutations
- There are some additional mutations we'd want to add (and then also add the resolvers) based on everything in the create route. I started adding these, but wanted to make sure we had the resolvers for connecting collections together.
- They'd share the same shape. I stopped after `createRaid` because I wanted to think through the connected resolvers.
- I commented out some of the fields until we figure out the nested resolvers (although that may not be necessary, we may handle that on the query side)
```graphql
createRaid: async (_, args, context, info) => {
const {
raid_name,
status,
category,
cleric_name,
roles_required,
// raid_party,
invoice_address,
start_date,
end_date,
// comments,
// related_raids,
} = args.raid;
const newRaid = new raid({
raid_name,
status,
category,
cleric_name,
roles_required,
// raid_party,
invoice_address,
start_date,
end_date,
// comments,
// related_raids,
// portfolio,
});
await raid.create(newRaid);
console.log(newRaid);
return newRaid;
},
```