@jdrydn/graphql-keyvalue
v1.1.0
Published
[![NPM](https://badge.fury.io/js/graphql-keyvalue.svg)](https://npm.im/graphql-keyvalue) [![CI](https://github.com/jdrydn/graphql-scalars/actions/workflows/ci.yml/badge.svg)](https://github.com/jdrydn/graphql-scalars/actions/workflows/ci.yml)
Downloads
2
Readme
graphql-keyvalue
Standalone GraphQL Scalar type for Key-Value hashes in JavaScript.
type User {
id: ID!
name: String!
state: KeyValue!
}
extend type Query {
user: User!
}
extend type Mutation {
updateUserState(id: ID!, state: KeyValue!): KeyValue!
}
Install
$ npm install --save graphql @jdrydn/graphql-keyvalue
From your codebase, you can either use predefined items (type definition & resolver) directly in your project or define the scalar yourself & include the scalar instance in your resolvers.
The following example uses graphql-tools
& the predefined items:
const assert = require('assert');
const { typeDefs: keyValueTypeDefs, resolvers: keyValueResolvers } = require('@jdrydn/graphql-keyvalue');
const typeDefs = /* GraphQL */`
type User {
id: ID!
name: String!
email: String!
state: KeyValue!
}
type Query {
user(id: ID!): User!
}
type Mutation {
updateUserState(id: ID!, state: KeyValue!): KeyValue!
}
`;
const resolvers = {
Query: {
async user(_, { id }) {
const user = await getUser(id);
return user && user.id ? user : null;
},
},
Mutation: {
async updateUserState(_, { id, state }) {
const user = await getUser(id);
assert(user && user.id, 'User not found');
// Merge in the user state
user.state = { ...user.state, ...state };
await setUser(id, user);
return user.state;
},
},
};
const schema = makeExecutableSchema({
typeDefs: [ typeDefs, keyValueTypeDefs ],
resolvers: [ resolvers, keyValueResolvers ],
});
Whereas this example uses apollo-server
& includes the scalar instance KeyValue
in its resolvers:
const { ApolloServer } = require('apollo-server');
const { KeyValue } = require('@jdrydn/graphql-keyvalue');
const typeDefs = /* GraphQL */`
type User {
id: ID!
name: String!
email: String!
state: KeyValue!
}
type Query {
user(id: ID!): User!
}
type Mutation {
updateUserState(id: ID!, state: KeyValue!): KeyValue!
}
# @NOTE You must define the scalar yourself
scalar KeyValue
`;
const resolvers = {
Query: {
async user(_, { id }) {
const user = await getUser(id);
return user && user.id ? user : null;
},
},
Mutation: {
async updateUserState(_, { id, state }) {
const user = await getUser(id);
assert(user && user.id, 'User not found');
// Merge in the user state
user.state = { ...user.state, ...state };
await setUser(id, user);
return user.state;
},
},
KeyValue,
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
Usage
Once the type definition & resolver is configured, you can send & receive simple key-value objects in GraphQL in both queries & mutations.
Query
query GetUser {
user(id: "1") {
id
name
state
}
}
{
"data": {
"user": {
"id": "1",
"name": "jdrydn",
"state": {
"signedInWith": "APPLE",
"finishedOnboarding": true
}
}
}
}
Mutation
mutation UpdateUser {
updateUserState(id: "1", state: { "finishedOnboarding": true })
}
{
"data": {
"updateUserState": {
"signedInWith": "APPLE",
"finishedOnboarding": true
}
}
}
Notes
- The scalar will pass an object for input values & expects an object to be passed for output values.
- Trying to send/receive a JSON object/array will throw an error.
- Why only one-level deep? One of the benefits of GraphQL is the strictly typed schema that is produced. This isn't trying to defy the GraphQL schema, merely extend it to cover more use-cases.
- After more than one level? Check out graphql-type-json.
- Any questions or suggestions please open an issue.