@thuoe/gql-util-directives
v1.3.0
Published
A simple utility package of GraphQL schema directives
Downloads
7
Maintainers
Readme
Get started
Install package:
npm install --save @thuoe/gql-util-directives
Example of importing the @regex
directive & instantiating with Apollo Server:
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { makeExecutableSchema } from "@graphql-tools/schema";
import directives from "@thuoe/gql-util-directives";
const typeDefs = String.raw`#graphql
type User {
firstName: String
lastName: String @regex(pattern: "\\b[A-Z]\\w+\\b")
age: Int
}
type Query {
user: User
}
`;
const resolvers = {
Query: {
user: () => ({
firstName: "Michael",
lastName: "Jordan",
age: 61,
}),
},
};
const { regexDirective } = directives;
const { regexDirectiveTypeDefs, regexDirectiveTransformer } =
regexDirective("regex");
const transformers = [regexDirectiveTransformer];
let schema = makeExecutableSchema({
typeDefs: [regexDirectiveTypeDefs, typeDefs],
resolvers,
});
schema = transformers.reduce(
(curSchema, transformer) => transformer(curSchema),
schema,
);
const server = new ApolloServer({
schema,
});
startStandaloneServer(server, {
listen: { port: 4000 },
}).then(({ url }) => {
console.log(`🚀 Server ready at: ${url}`);
});
Here are the possible directive functions that are exposed as part of this util package:
regexDirective | encodingDirective | cacheDirective
Local Development
Install local dependencies:
npm install
Run local environment (Apollo Studio):
npm run dev
Link to Apollo Studio can be found on http://localhost:4000 to perform mutations and queries.
Directives
@encode
encodingDirective(directiveName?: string)
You can use the @encode
directive on fields defined using the String
scalar type.
Following encoding methods:
ascii | utf8 | utf16le | ucs2 | base64 | base64url | latin1 | binary | hex
type User {
firstName: String @encode(method: "hex")
lastName: String @encode(method: "base64")
}
@regex
regexDirective(directiveName?: string)
You can use the @regex
directive to validate fields using the String
scalar type. It will throw an
ValidationError
in the event that the pattern defined has a syntax if no matches are found against the field value.
type User {
firstName: String @regex(pattern: "(John|Micheal)")
lastName: String @regex(pattern: "\\b[A-Z]\\w+\\b")
}
⚠️ Escaping characters
If you are defining a regex pattern using backslashes must escape them (//
) and pattern invoke the function String.raw()
to the schema so that the escape characters are not ignored:
const typeDefs = String.raw`
type User {
firstName: String @regex(pattern: "(Eddie|Sam)")
lastName: String @regex(pattern: "\\b[A-Z]\\w+\\b")
age: Int
}
type Query {
user: User
}
`;
@cache
cacheDirective({ directiveName, cache }?: { directiveName?: string, cache?: CachingImpl })
You can use @cache
directive to take advantage of a in-memory cache for a field value
type Book {
name: String
price: String @cache(key: "book_price", ttl: 3000)
}
key
- represents the unique key for field value you wish to cache
ttl
- time-to-live argument for how long the field value should exist within the cache before expiring (in milliseconds)
Overriding in-memory cache
If you wish to take leverage something more powerful (for example Redis), you can override the in-memory solution with your own implementation.
Example:
import Redis from 'ioredis'
const redis = new Redis()
....
const cache = {
has: (key: string) => redis.exists(key),
get: (key: string) => redis.get(key),
delete:(key: string) => redis.delete(key),
set: async (key: string, value: string) => {
await redis.set(key, value)
},
}
...
const { cacheDirectiveTypeDefs, cacheDirectiveTransformer } = cacheDirective({ cache: callback })
You must confirm to this set of function signatures to make this work:
has: (key: string) => Promise<boolean>
Checks if a key exists in the cache.get: (key: string) => Promise<string>
Retrieves the value associated with a key from the cache.set: (key: string, value: string) => Promise<void>
Sets a key-value pair in the cache.delete: (key: string) => Promise<boolean>
Deletes a key and its associated value from the cache.
@currency
currencyDirective(directiveName?: string)
You can use the @currency
directive to fetch the latest exchange rate of a given amount
type Car {
make: String
model: String
price: String @currency(from: GBP, to: USD)
}
The field can either be resolved with scalar types String
or Float
The valid currency codes to use as part of the directive's arguments can be found here.
@log
logDirective({ directiveName, filePath }?: { directiveName?: string, filePath?: string })
Use the @log
directive to log fields, queries and mutations once they are resolved.
For example, this graphql schema with the directive on the query:
type User {
firstName: String
lastName: String
age: Int
amount: String
}
type Query {
user(firstName: String!): User @log(level: INFO)
}
Will log to the console in the following format:
[<TIMESTAMP>] [INFO] @log - Operation Type: query, Arguments: [{"firstName":"Eddie"}], Return Type: User
The following log levels are valid:
INFO
DEBUG
WARN
ERROR
Logging to file
In order to migrate logs to a custom log file, you can define a filepath with the appropriate file name:
const { logDirectiveTypeDefs, logDirectiveTransformer } = logDirective({
filePath: path.join(__dirname, 'logs', 'application.log')
})