{"id":15020087,"url":"https://github.com/imqueue/graphql-dependency","last_synced_at":"2026-03-07T05:07:56.129Z","repository":{"id":35855568,"uuid":"216524250","full_name":"imqueue/graphql-dependency","owner":"imqueue","description":"Cross service dependencies for GraphQL API with underlying @imqueue services","archived":false,"fork":false,"pushed_at":"2025-09-11T11:39:48.000Z","size":740,"stargazers_count":17,"open_issues_count":3,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-10-11T08:55:13.540Z","etag":null,"topics":["data-loader","dependency-graph","dependency-loader","ecosystem","graphql","graphql-api","graphql-dependency","loaders","resolver"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/imqueue.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-10-21T09:05:48.000Z","updated_at":"2025-09-11T11:39:52.000Z","dependencies_parsed_at":"2023-01-16T07:41:33.397Z","dependency_job_id":"30b91c8f-7069-48c7-b30d-672ae9d3334b","html_url":"https://github.com/imqueue/graphql-dependency","commit_stats":{"total_commits":58,"total_committers":2,"mean_commits":29.0,"dds":"0.051724137931034475","last_synced_commit":"fe24b934e57228f581ef7fe5e7cf94de1178e722"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/imqueue/graphql-dependency","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imqueue%2Fgraphql-dependency","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imqueue%2Fgraphql-dependency/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imqueue%2Fgraphql-dependency/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imqueue%2Fgraphql-dependency/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/imqueue","download_url":"https://codeload.github.com/imqueue/graphql-dependency/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imqueue%2Fgraphql-dependency/sbom","scorecard":{"id":486284,"data":{"date":"2025-08-11","repo":{"name":"github.com/imqueue/graphql-dependency","commit":"dbf41f7c187e4a9a545a1e098839172aebbb8750"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.7,"checks":[{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/imqueue/graphql-dependency/build.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/imqueue/graphql-dependency/build.yml/master?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/build.yml:26","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Code-Review","score":0,"reason":"Found 1/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":4,"reason":"5 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 4","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T17:54:12.114Z","repository_id":35855568,"created_at":"2025-08-19T17:54:12.114Z","updated_at":"2025-08-19T17:54:12.114Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30208730,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T03:24:23.086Z","status":"ssl_error","status_checked_at":"2026-03-07T03:23:11.444Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["data-loader","dependency-graph","dependency-loader","ecosystem","graphql","graphql-api","graphql-dependency","loaders","resolver"],"created_at":"2024-09-24T19:54:34.299Z","updated_at":"2026-03-07T05:07:51.118Z","avatar_url":"https://github.com/imqueue.png","language":"TypeScript","readme":"# @imqueue/graphql-dependency\n\n[![Build Status](https://img.shields.io/github/actions/workflow/status/imqueue/graphql-dependency/build.yml)](https://github.com/imqueue/graphql-dependency)\n[![codebeat badge](https://codebeat.co/badges/87c59873-d921-4a57-981b-9f8e0743776b)](https://codebeat.co/projects/github-com-imqueue-graphql-dependency-master)\n[![Coverage Status](https://coveralls.io/repos/github/imqueue/graphql-dependency/badge.svg?branch=master)](https://coveralls.io/github/imqueue/graphql-dependency?branch=master)\n[![Known Vulnerabilities](https://snyk.io/test/github/imqueue/graphql-dependency/badge.svg?targetFile=package.json)](https://snyk.io/test/github/imqueue/graphql-dependency?targetFile=package.json)\n[![License](https://img.shields.io/badge/license-ISC-blue.svg)](https://rawgit.com/imqueue/cli/master/LICENSE)\n\nCross-service GraphQL dependency loading during query calls for @imqueue\necosystem.\n\n# Install\n\n~~~bash\nnpm i --save @imqueue/graphql-dependency\n~~~\n\n# Usage\n\nThis module allows to describe cross-service dependencies and fetch user \nrequested data in an optimal manner. Let's imagine we have 2 micro-services\nserving `User` and `Company` data respectively. Let's assume User can be \na team member of the Company. As well as Company can have User as an owner.\n\nOn GraphQL API level it may be represented by a following schema:\n\n~~~graphql\ntype User {\n    id: ID!\n    name: String!\n    email: String!\n    phone: String!\n    ownerOf: [Company]\n    memberOf: [Company]\n}\ntype Company {\n    id: ID!\n    name: String!\n    description: String!\n    ownerId: Int!\n    owner: User\n    members: [User]\n}\n~~~ \n\nNow we have a query which can fetch a user with all related data, like this:\n\n~~~graphql\nquery user(id: \"VXNlcjox\") {\n    id\n    name\n    email\n    phone\n    ownerOf {\n        id\n        name\n        members {\n            id\n            name\n            phone\n        }\n    }\n    memberOf {\n        id\n        name\n        owner {\n            id\n            name\n            email\n            phone\n        }\n    }\n}\n~~~\n\nAs seen from such query we would need to implement resolver recursively loading\ncompanies data for user and user data for companies.\n\nWith this module it's possible to resolve such dependencies automatically and\nfetch data in a most efficient way using caching and minimizing number of\nrequest by defining the dependencies between entities and their loaders and \ninitializers.\n\n~~~typescript\nimport { Dependency } from '@imqueue/graphql-dependency';\nimport {\n    GraphQLID,\n    GraphQLList,\n    GraphQLNonNull,\n    GraphQLObjectType,\n    GraphQLString,\n} from 'graphql';\nimport { globalIdField } from 'graphql-relay';\n// we referring @imqueue based clients here\nimport { userClient, companyClient } from '../clients';\n\n/**\n * User type definition\n */\nexport const User = new GraphQLObjectType({\n    name: 'User',\n    fields: () =\u003e ({\n        id: globalIdField(\n            User.name,\n            (user: userClient.User) =\u003e user.id + '',\n        ),\n        name: {\n            type: new GraphQLNonNull(GraphQLString),\n            resolve: (user: userClient.User) =\u003e user.name,\n        },\n        phone: {\n            type: new GraphQLNonNull(GraphQLString),\n            resolve: (user: userClient.User) =\u003e user.name,\n        },\n        email: {\n            type: new GraphQLNonNull(GraphQLString),\n            resolve: (user: userClient.User) =\u003e user.name,\n        },\n        ownerOf: {\n            type: new GraphQLList(Company),\n            resolve: (user: userClient.user) =\u003e user.name\n        }\n    }),\n});\n\n/**\n * Defining user type loader.\n * Loader defines how the entity should be loaded when it is a dependency of\n * another object. Fo example, When company needs to load a user it will call\n * this loader to fill the fields of User type. \n */\nDependency(User).defineLoader(async (\n    context: any,\n    filter: any,\n    fields: any,\n): Promise\u003cArray\u003cPartial\u003cuserClient.User\u003e\u003e\u003e =\u003e\n    // meaning context contain initialized user service client reference\n    // BTW loader could implement any functionality fetching users list by\n    // a given filter returning requested user fields\n    // @see https://github.com/Mikhus/graphql-fields-list library, for example,\n    // to extract fields map input from graphql request info object\n    // Filter would contain data constructed from parent objects data set\n    // using the Dependency filtering options defined in the require() calls.\n    await context.user.list(filter, fields),\n);\n\n/**\n * Company type definition\n */\nexport const Company = new GraphQLObjectType({\n    name: 'Company',\n    fields: () =\u003e ({\n        id: globalIdField(\n            Company.name,\n            (company: companyClient.Company) =\u003e company.id + '',\n        ),\n        name: {\n            type: new GraphQLNonNull(GraphQLString),\n            resolve: (company: companyClient.Company) =\u003e company.name,\n        },\n        description: {\n            type: new GraphQLNonNull(GraphQLString),\n            resolve: (company: companyClient.Company) =\u003e company.description,\n        },\n        ownerId: {\n            type: new GraphQLNonNull(GraphQLID),\n            resolve: (company: companyClient.Company) =\u003e company.ownerId,\n        },\n        owner: {\n            type: User,\n            resolve: (company: companyClient.Company) =\u003e company.owner,\n        },\n        members: {\n            type: new GraphQLList(User),\n            resolve: (company: companyClient.Company) =\u003e company.members,\n        },\n    }),\n});\n\n/**\n * Defining company type loader\n */\nDependency(Company).defineLoader(async (\n    context: any,\n    filter: any,\n    fields: any,\n): Promise\u003cArray\u003cPartial\u003ccompanyClient.Company\u003e\u003e\u003e =\u003e\n    // meaning context contain initialized company service client reference\n    await context.company.list(filter, fields),\n);\n\n/**\n * Describing dependencies\n */\nDependency(Company).require(User, () =\u003e ({\n    as: Company.getFields().owner,\n    filter: {\n        // here we assume that user loader implements fetching users list\n        // by a filter containing list of user identifiers\n        [User.getFields().id.name]: Company.getFields().ownerId,\n    },\n}), () =\u003e ({\n    as: Company.getFields().members,\n    filter: {\n        // here we assume that user loader implements fetching list of users\n        // by a filter containing list of related company identifiers\n        'relatedCompanyIds': Company.getFields().id,\n    },\n}));\n\nDependency(User).require(Company, () =\u003e ({\n    as: User.getFields().memberOf,\n    filter: {\n        'relatedMemberIds': User.getFields().id,\n    },\n}), () =\u003e ({\n    as: User.getFields().ownerOf,\n    filter: {\n        [Company.getFields().ownerId]: User.getFields().id,\n    },\n}));\n~~~\n\nWith this setup we assume that user and company loaders implements data fetching\nby a defined dependency requirement filters. @imqueue ecosystem provides a\nstraightforward way dealing with filters/fields fetched from a user request,\nor you can implement it any suitable way, for example having loaders \nimplementation which directly makes database or key-value storage calls without\nthe need to create service layer.\n\nThen on query implementation resolver we would act as this:\n\n~~~typescript\nasync function resolve(\n    source: any,\n    args: any,\n    context: any,\n    info: GraphQLResolveInfo,\n) {\n    const fields = fieldsMap(info);\n    const user = context.user.find(fromGlobalId(args.id).id);\n\n    if (user) {\n        // this call will fetch all dependent data and map it to a resulting\n        // user object (modifying it)\n        await Dependency(User).load([user], context, fields);\n    }\n\n    // now we are safe to return all the source data requested\n    return user;\n}\n~~~\n\nDependency loader will do all the job calling the minimum amount of requests\nrequired to fill the result data. If end user created a request containing\nrecursive nesting which falls into fetching process of the same data recursively\nit will end up in a data mapping without an additional calls for each nesting\nlevels. Most of the data are not copied and is mapped by references, so the\nmemory footprint will be kept on minimal level as well.\n\n## License\n\nThis project is licensed under the GNU General Public License v3.0.\nSee the [LICENSE](LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimqueue%2Fgraphql-dependency","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimqueue%2Fgraphql-dependency","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimqueue%2Fgraphql-dependency/lists"}