{"id":26267364,"url":"https://github.com/oslabs-beta/desolver","last_synced_at":"2025-10-16T23:32:34.528Z","repository":{"id":40339009,"uuid":"457179607","full_name":"oslabs-beta/DeSolver","owner":"oslabs-beta","description":"DeSolver is a lightweight, Node.js, GraphQL library providing a powerful yet approachable API for composing modular resolver business logic.","archived":false,"fork":false,"pushed_at":"2022-06-15T02:03:21.000Z","size":1351,"stargazers_count":80,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"npm_DeSolver","last_synced_at":"2025-07-05T18:53:31.130Z","etag":null,"topics":["apollo-server-express","graphql","graphql-tools","node-redis","redis"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oslabs-beta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-09T02:29:15.000Z","updated_at":"2025-05-28T16:01:16.000Z","dependencies_parsed_at":"2022-08-09T17:40:35.005Z","dependency_job_id":null,"html_url":"https://github.com/oslabs-beta/DeSolver","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/oslabs-beta/DeSolver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oslabs-beta%2FDeSolver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oslabs-beta%2FDeSolver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oslabs-beta%2FDeSolver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oslabs-beta%2FDeSolver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oslabs-beta","download_url":"https://codeload.github.com/oslabs-beta/DeSolver/tar.gz/refs/heads/npm_DeSolver","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oslabs-beta%2FDeSolver/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264456022,"owners_count":23611069,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apollo-server-express","graphql","graphql-tools","node-redis","redis"],"created_at":"2025-03-14T04:16:38.355Z","updated_at":"2025-10-16T23:32:34.430Z","avatar_url":"https://github.com/oslabs-beta.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\" \u003e\n\u003cimg src = \"assets/orangesphere_web.gif\" width=\"250\"/\u003e\n\u003c/p\u003e\n \n\u003ch1 align=\"center\"\u003eDeSolver\u003c/h1\u003e\n\u0026nbsp;\n \n## Table of Contents\n \n- [About](https://github.com/oslabs-beta/DeSolver/#about)\n- [Getting Started](https://github.com/oslabs-beta/DeSolver/#gettingstarted)\n- [How to Use](https://github.com/oslabs-beta/DeSolver/#howtouse)\n   - [DeSolver Instance](https://github.com/oslabs-beta/DeSolver/#desolverinstance)\n   - [Cache](https://github.com/oslabs-beta/DeSolver/#cache)\n   - [Desolver Fragments](https://github.com/oslabs-beta/DeSolver/#desolverfragments)\n   - [Creating Middleware Pipeline](https://github.com/oslabs-beta/DeSolver/#pipeline)\n   - [Targeting a specific resolver type](https://github.com/oslabs-beta/DeSolver/#targetatype)\n   - [Define resolvers as multiple fragments](https://github.com/oslabs-beta/DeSolver/#multiplefragments)\n- [Contributors](https://github.com/oslabs-beta/DeSolver/#team)\n- [License](https://github.com/oslabs-beta/DeSolver/#license)\n \n\u003cp\u003e\u003cbr\u003e\n\u003ch2 href=\"#about\"\u003e\u003c/h2\u003e\n \n# About\n \nDeSolver for [GraphQL](https://graphql.org/): a lightweight, minimalist, unopinionated Node.js GraphQL framework providing a powerful yet approachable API for composing modular and reusable resolver business logic. DeSolver utilizes the middleware pattern as seen in other popular frameworks as a way to create \"routing\" for your resolvers.\n \nThe DeSolver instance methods allow a pipeline to be loaded with mini-resolver functions, and a wrapper forms around the resolver map object, permitting a series of functions in a chain or \"pre-hook\" functions to execute prior to a query or mutation. This minimizes the need to wrap individual resolver functions manually, thereby reducing templating and additional boilerplate. Composing resolvers in this way can help keep resolver code more maintainable, scalable and testable. DeSolver follows the \"write once, run everywhere\" mantra.\n \n\u003cp\u003e\u003cbr\u003e\n \n\u003ch2 href=\"#gettingstarted\"\u003e \u003c/h2\u003e\n \n# Getting Started\n\n1. Installing DeSolver\n\n- Start by running the npm command:\n\n```javascript\nnpm install desolver\n```\n\n- The DeSolver framework works best when combined with [GraphQL tools](https://www.graphql-tools.com/docs/generate-schema) Executable Schema package. It is recommended to download that package and use that to generate your type definitions, resolver map and schema.\n\n- The DeSolver framework is compatible with the popular Apollo Server API. DeSolver can be utilized when combined with the resolver map object in Apollo Server.\n\n- Redis is used for caching resolvers. Check out [Redis](https://redis.io) and [node-redis](https://github.com/redis/node-redis) for installation details. When not using Redis or when using custom caching logic, DeSolver provides a configuration option to disable this default behavior.\n\n\u003cp\u003e\u003cbr\u003e\n \n\u003ch2 href=\"#howtouse\"\u003e\u003c/h2\u003e\n\n# How to use\n\n\u003ch3 href=\"#desolverinstance\"\u003e\u003c/h3\u003e\n \n### **Desolver Instance and Configuration**\n \nIn your GraphQL server or resolvers file create a new instance of DeSolver:\n \n```javascript\nconst desolver = new Desolver(desolverConfig)\n```\n \nThe following optional configuration object can be declared as the argument of the DeSolver constructor:\n \n```javascript\nconst desolverConfig = {\n cacheDesolver?: boolean, // set to true to enable Redis caching\n applyResolverType?: string // resolver type to target for running prehooks\n}\n```\n \n- `cacheDesolver`: Set to `true` to enable Redis caching, by default if nothing is passed, the default redis instance will be started. Set to `false` to disable this behavior.\n \nThe desolverConfig object can also be defined with configuration options from Redis. See [node-redis](https://github.com/redis/node-redis) for a list of additional custom configuration options that can be defined from Redis.\n\u003cbr\u003e\u003cbr\u003e\n \n\u003ch3 href=\"#cache\"\u003e\u003c/h3\u003e\n \n### **Cache**\n \nDeSolver utilizes Redis caching for greater query optimization. If `cacheDesolver` option is set to `true`, this will enable automated caching of resolver queries. DeSolver will automatically generate a unique key for the Redis cache based on path property from within the info argument. Set the `cacheDesolver` property to `false` if you would like to disable this default behavior and provide your own caching logic.\n\u003cbr\u003e\u003cbr\u003e\n \n\u003ch3 href=\"#desolverfragments\"\u003e\u003c/h3\u003e\n \n### **DeSolver Fragments**\n \nDeSolver Fragments are used as versions of middleware functions. Each resolver can be decomposed into a series of \"fragment\" functions. To maintain full functionality of a normal resolver, it provides the current field resolvers first four arguments (root/parent, arguments, context, and info), as well as three additional custom parameters (next, escape, and ds).\n \n```javascript\nconst desolverFragment = (parent, args, context, info, next, escapeHatch, ds) =\u003e {\n // write your resolver business logic here\n // parent, args, context and info are available for use here\n // ds context object is also provided by this framework\n \n // @return\n   // next() - calls the next function in the middleware chain\n   // escapeHatch(input) - pass a value to input to resolve immediately\n}\n```\n \nThe DeSolver Parameters are as follows:\n \nThe first four parameters are the normal parameters for any resolver:\n- `parent`: Sometimes referred to as the root object. The same parent/root object which is the result of the previous parent/type.\n- `arguments`: Arguments provided to the root or field resolver.\n- `context`: an object that is provided to all resolvers.\n- `info`: field specific information relevant to the query.\n \nThe final three parameters are additional parameters provided by the DeSolver framework:\n- `next`: Calls the next DeSolver Fragment in the middleware chain.\n- `escapeHatch`: Immediately resolves the current root or field resolver.\n- `ds`: A context object that can be passed from one DeSolver Fragment to the next. Similar in functionality to res.locals in the Express framework.\n\u003cbr\u003e\u003cbr\u003e\n\u003ch3 href=\"#pipeline\"\u003e\u003c/h3\u003e\n \n### **Creating the middleware pipeline**\n \nUtilize the `desolver.use()` method on the desolver instance to generate your pipeline of prehook functions.\n\nThe `desolver.use()` method has the following parameters:\n- `ResolverType`: A string which matches the Resolver Type in your Resolver Map object. Pass the string `'All'` if you want to chain the prehook functions to all your resolvers.\n- `DeSolverFragments`: Add any number of functions in the form of DeSolver Fragments to chain to the target Resolver Type. \n\nMultiple successive invocations of `desolver.use()` will also add additional functions to the pipeline.\n \nThe following is an example use case for the desolver middleware pipeline involving guarding root queries with authentication logic:\n \n```javascript\nconst desolver = new Desolver()\n \n// Declare authentication Desolver Fragment Function\nconst authentication = (parent, args, context, info, next, escapeHatch, ds) =\u003e {\n // Define some authentication logic here using args or context\n // throw error if not authenticated\n}\n \n// Add the authentication function to pipeline with desolver.use()\n// This function will execute prior to all Query resolvers\ndesolver.use('Query', authentication)\n \n// Invoke desolver.apply() method with the resolver map object passed\nconst resolvers = desolver.apply({\n Query: {\n   getUserById: (parent, args, context, info) =\u003e {\n     // this root query is now guarded by the authentication function\n   },\n \n   getPostsById: (parent, args, context, info) =\u003e {\n     // this root query is now guarded by the authentication function\n   },\n }\n \n // Additional resolvers here\n})\n```\n\u003cbr\u003e\u003cbr\u003e\n\u003ch3 href=\"#multiplefragments\"\u003e\u003c/h3\u003e\n \n### **Define resolvers as multiple DeSolver fragments**\n \nDefining root or field level resolvers as a chain of DeSolver fragments is a resolver function declared utilizing `desolver.useRoute()`.  The `useRoute` method takes any number of Desolver Fragment middleware functions and forms a \"route\" for the root or field resolver.\n \nAll methods `desolver.use()`, `desolver.apply()`, and `desolver.useRoute()` can be utilized together to form a more modular and scalable way to compose resolvers.\n \nSee the example below:\n \n```javascript\n// desolver.use(), desolver.apply() and desolver.useRoute() can\n// be used together to create longer chains\n \ndesolver.use('Query', authentication)\n \nconst resolvers = desolver.apply({\n Query: {\n   // Define your resolver using desolver.useRoute() and add\n   // any number of desolver fragments to modularize resolver logic\n   // The authentication function will execute followed by desolverFragment1\n   // and desolverFragment2\n   getUserById: desolver.useRoute(desolverFragment1, desolverFragment2),\n \n   // desolver.use(), desolver.apply(), desolver.useRoute() and\n   // normal resolver functions used together seamlessly throughout the\n   // resolver map\n   getPostsById: (parent, { id }, context, info) =\u003e {\n     return ctx.db.findPosts(id)\n   },\n }\n})\n```\n\u003cbr\u003e\u003cbr\u003e\n \n\u003ch3 href=\"#targetatype\"\u003e\u003c/h3\u003e\n \n### **Targeting a specific resolver type**\n \nTo chain Desolver Fragments to a specific root type or field resolvers, multiple invocations of `desolver.use()` can be called with different Resolver Type targets.\n \nSee the example below:\n \n```javascript\ndesolver.use('Query', authentication)\n\ndesolver.use('Mutation', authentication, authorization)\n \nconst resolvers = desolver.apply({\n Query: {\n   // Query resolvers are guarded only by authentication function\n   getUserById: desolver.useRoute(desolverFragment1, desolverFragment2),\n \n   getPostsById: (parent, { id }, context, info) =\u003e {\n     return ctx.db.findPosts(id)\n   },\n }\n \n Mutation: {\n   createUser: (parent, root, args, context, info) =\u003e {\n    // This mutation resolver is now guarded by both authentication and authorization functions\n   }\n }\n})\n```\n\u003cp\u003e\u003cbr\u003e\n\u003ch3 href=\"#team\"\u003e\u003c/h3\u003e\n \n# **Contributors**\n \nDeSolver is an open-source community project on Github and accelerated by [OS Labs](https://opensourcelabs.io/). We are maintained by a small group of dedicated software engineers. We appreciate your participation, feedback, bug fixes and feature developments.\n \n\u003cp\u003e\u003cbr\u003e\n \n|                     | GitHub                           | LinkedIn                                        |\n| ------------------- | -------------------------------- | ----------------------------------------------- |\n| Michael Chan        | https://github.com/mckchan13     | https://www.linkedin.com/in/michael-ck-chan/    |\n| Mia Kang            | https://github.com/jcmiakang     | https://www.linkedin.com/in/mia-kang/           |\n| Alexander Gurfinkel | https://github.com/AlexGurfinkel | https://www.linkedin.com/in/alexandergurfinkel/ |\n| Julia Hickey        | https://github.com/hijulia1136   | https://www.linkedin.com/in/juliahickey/        |\n \n\u003cp\u003e\u003cbr\u003e\n\nIf you are interested in creating an open-source project that builds on top of DeSolver, please don't hesitate to reach out, and we'd be happy to provide feedback and support here or via [DeSolver LinkedIn](https://www.linkedin.com/company/desolver/).\n\n\u003cp\u003e\u003cbr\u003e\n\u003ch3 href=\"#license\"\u003e\u003c/h3\u003e\n \n# License\n \nThis product is licensed under the MIT License - see the LICENSE.md file for details.\n \nThis is an open source product.\n \nThis product is accelerated by [OS Labs](https://github.com/oslabs-beta).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foslabs-beta%2Fdesolver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foslabs-beta%2Fdesolver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foslabs-beta%2Fdesolver/lists"}