{"id":22358875,"url":"https://github.com/kon14/conduitmoduleexample","last_synced_at":"2025-10-19T22:49:21.948Z","repository":{"id":114229176,"uuid":"572611818","full_name":"kon14/ConduitModuleExample","owner":"kon14","description":"A minimal module implementation example for Conduit ⚡","archived":false,"fork":false,"pushed_at":"2023-10-04T21:51:08.000Z","size":160,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-31T15:18:40.058Z","etag":null,"topics":["backend","conduit","example","graphql","grpc","javascript","low-code","rest","typescript"],"latest_commit_sha":null,"homepage":"https://getconduit.dev","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/kon14.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}},"created_at":"2022-11-30T16:39:33.000Z","updated_at":"2023-09-30T20:35:13.000Z","dependencies_parsed_at":"2023-10-01T21:29:09.946Z","dependency_job_id":null,"html_url":"https://github.com/kon14/ConduitModuleExample","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kon14%2FConduitModuleExample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kon14%2FConduitModuleExample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kon14%2FConduitModuleExample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kon14%2FConduitModuleExample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kon14","download_url":"https://codeload.github.com/kon14/ConduitModuleExample/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245667748,"owners_count":20652983,"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":["backend","conduit","example","graphql","grpc","javascript","low-code","rest","typescript"],"created_at":"2024-12-04T15:18:10.575Z","updated_at":"2025-10-19T22:49:16.903Z","avatar_url":"https://github.com/kon14.png","language":"TypeScript","readme":"\u003cdiv align=\"center\"\u003e\n  \u003cbr\u003e\n    \u003ca href=\"https://getconduit.dev\" target=\"_blank\"\u003e\u003cimg src=\"https://getconduit.dev/conduitLogo.svg\" height=\"80px\" alt=\"logo\"/\u003e\u003c/a\u003e\n    \u003cbr/\u003e\n    \u003ch3\u003eThe only Backend you'll ever need.\u003c/h3\u003e\n\u003c/div\u003e\n\n# Conduit Module Example\n\nThis repo contains a minimal implementations for a [Conduit](https://github.com/ConduitPlatform/Conduit)\nmodule written in Node.js and TypeScript.\u003cbr /\u003e\n\nIt's meant to be referenced while reading through [Conduit's SDK Documentation](https://getconduit.dev/docs/sdk/)\nand used as a starting point for building your own Conduit modules.\n\nIt is assumed that you've already read through the aforementioned documentation,\nand any critical prerequisites that may list, and familiarized yourself with the concepts discussed.\n\nIf you need any sort of help or wish to suggest improvements over the code or docs,\ndo not hesitate to open an issue or let us know on our [Discord](https://discord.com/invite/fBqUQ23M7g).\n\n## Module Description 🧩\n\nOur application allows our users to receive free cookies 🍪 via client API requests,\nas long as our cookie resources are not depleted and their name is not blacklisted in our configuration.\n\nAs far as REST and GraphQL APIs are concerned, we offer two client endpoints for receiving cookies.\u003cbr /\u003e\nOne of them is unprotected, while the other one requires user authentication.\u003cbr /\u003e\nThere's also an administrative endpoint for updating our cookie stocks.\n\nWhen it comes to gRPC, we also provide two administrative RPCs for receiving and replenishing cookies.\u003cbr /\u003e\nCookies are also automatically replenished on service startup.\n\nOur module's configuration allows us to specify an array of names that won't be receiving cookies,\ndisable the unauthenticated cookie retrieving endpoint and set the starting amount of cookies\n(also used on resets without an explicitly specified cookie count value).\n\nWe utilize Prometheus metrics for tracking the total amount of cookie requests received and the count for currently available cookies.\u003cbr /\u003e\nWe also log informational messages and errors through Loki.\n\n_Tip: Conduit automatically generates documentation for both REST (Swagger) and GraphQL endpoints._\n\nAdministrative APIs:\n- gRPC\n- REST\n- GraphQL (optionally enabled through Conduit's Admin Panel)\n\nApplication APIs:\n- REST\n- GraphQL\n\n## Building 🔨\n\nIt is assumed that you are building and running this in a Linux or macOS environment.\u003cbr /\u003e\nIf you're using Windows, make sure you're using WSL.\n\nBefore proceeding, verify you've got [protoc](https://github.com/protocolbuffers/protobuf/releases) installed on your system.\n\n``` bash\n# Install Dependencies\nnpm run setup\n\n# Build Module\nnpm run build\n```\n\n## Running 💻\n\nWe assume that you've already brought up a Conduit deployment using the [Conduit CLI](https://getconduit.dev/docs/cli).\u003cbr /\u003e\nMake sure your deployment's major version matches the one of the example module implementation being used!\n\nIf you don't intend to use the default deployment configuration provided by Conduit CLI\n(eg: by running Conduit directly on the host), make sure that you update the provided `.env` file.\n\n``` bash\n# Start Module\nnpm run start\n```\n\n## Docker 📦\n\nYou may alternatively build and run this in a container.\u003cbr /\u003e\nThe following assumes you're connecting to a deployment configured via the CLI.\n\n``` bash\n# Build the Docker image\ndocker build -t conduit-module-example . -f Dockerfile\n\n# Run the container\ndocker run -it -p 55200:55200 -e CONDUIT_SERVER=\"conduit:55152\" -e SERVICE_URL=\"conduit-module-example:55200\" \\\n-e GRPC_PORT=\"55200\" -e METRICS_PORT=\"9200\" -e LOKI_URL=\"http://conduit-loki:3100\" -e GRPC_KEY=\"\" \\\n--network conduit --network-alias conduit-module-example --name conduit-module-example conduit-module-example\n```\n\n## Now What 🤔\n\nWe suggest that you start out by verifying your module's example endpoints are registered and operational.\u003cbr /\u003e\nOnce you get a grasp of how the code comes together, you may proceed to altering its behavior and expanding its functionality.\n\nBringing up Conduit through the CLI should have already redirected you to your admin dashboard.\u003cbr /\u003e\nYou may locate the Swagger and GraphQL related resources referenced below through the relevant elements in the home page.\n\n_Tip: Default Admin Credentials: `admin/admin`_\n\n## Performing Requests\n\nThis section assumes that you are already aware of how to utilize Conduit's\n[user](../modules/authentication/strategies) and [admin](../administration) authentication headers.\u003cbr /\u003e\nAdditionally, the application APIs' [security clients](../modules/router/security) are assumed to be disabled.\n\n### REST\nYou may perform REST requests and browse your endpoint documentation directly through Swagger UI,\nor by importing your APIs' Swagger JSON files to an HTTP API testing tool of your choice.\n\nWe'll proceed with a few `curl` examples to get you started:\n\n#### Getting Cookies\n\nLet's start off by simply requesting a cookie.\u003cbr /\u003e\nWe'll go by Stan for this one, as that name is not blacklisted in the default configuration.\n\n``` bash title=\"Get Cookie (Unauthenticated)\"\ncurl --location 'http://localhost:3000/exampleModule/cookies/guest?name=Stan' \n```\n``` bash title=\"Response\"\n{\n    \"result\": \"Hey there Stan, have a cookie 🍪.\"\n}\n```\n\nGreat, we got our first cookie, hopefully they're not keeping tabs on us, so we can ask for more soon.\nLet's try once more, this time going by Betty.\n\n``` bash title=\"Get Cookie (Unauthenticated)\"\ncurl --location 'http://localhost:3000/exampleModule/cookies/guest?name=Betty' \n```\n``` bash title=\"Response\"\n{\n    \"result\": \"I'm sorry Betty, no cookies for you today 💅.\"\n}\n```\n\nOuch, that hurt. But hey, thankfully for Betty and regrettably for our application,\nclients can provide any name they wish and our endpoint will gladly accept that.\n\nMoving on, let's try the proper user authenticated endpoint.\u003cbr /\u003e\nWe assume you already know how to [create and authenticate your users](../modules/authentication/strategies)\nand have already obtained our own user authentication token.\n\n``` bash title=\"Get Cookie (User Authentication)\"\ncurl --location --request GET 'http://localhost:3000/exampleModule/cookies' \\\n     --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYzODhjZTVlZTFlMDAzYjdmZGU4YzY1ZiIsImF1dGhvcml6ZWQiOnRydWUsInN1ZG8iOnRydWUsImlhdCI6MTY2OTk5MjYzNiwiZXhwIjoxNjczNTkyNjM2fQ.oCAELwBektsfINwa1EaxmrhtSVuhM7xvcccf2xQb948'\n```\n``` bash title=\"Response\"\n{\n    \"result\": \"Hey there guacamole.lover97, have a cookie 🍪.\"\n}\n```\n\nThat's a weird looking name, what's going on here and where did we even get a name for this?\u003cbr /\u003e\nLooking into our endpoint's implementation you'll realize we're basically stripping off the user's email prefix\nand using that as the implicitly provided name for our cookie request.\n\n``` typescript title=\"GetCookieAuthenticated Handler Snippet\"\nconst user: User = call.request.context.user;\nconst name = user.email.split('@')[0];\n```\n\nThe Authentication module's User schema does not have a `firstName` or `lastName` field attached to it.\u003cbr /\u003e\nThat is simply because not all application use cases require that it does.\u003cbr /\u003e\nYou may still extend the schema as you see fit by providing additional fields for it both through\nthe Database module's CMS functionality available right in your admin panel, or through your custom microservice.\u003cbr /\u003e\nYou may then update this endpoint to utilize your extension field instead.\n\nAs a final step, let's modify our name blacklist through an administrative module configuration request.\u003cbr /\u003e\nWe'll start by viewing our existing configuration.\n\nWe assume you're already aware of [how to work with admin authentication headers](../administration).\n\n``` bash title=\"Get Module Configuration (Admin Authentication)\"\ncurl --location --request GET 'http://localhost:3030/config/exampleModule/' \\\n     --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYzN2FiNzE3NjYxMzk4ZDUzNTBhZjhmYyIsImlhdCI6MTY2OTk5MjE1MSwiZXhwIjoxNjcwMDY0MTUxfQ.lgLnkrx_FDlUCsD5wNtXfMc3GKG41Eq7xN4BrnMznrw' \\\n     --header 'masterkey: M4ST3RK3Y' \\\n     --header 'Content-Type: application/json'\n```\n``` bash title=\"Response\"\n{\n    \"config\": {\n        \"active\": true,\n            \"defaultCookieCount\": 20,\n            \"illegalNames\": [\n                \"Alex\",\n                \"Betty\",\n                \"Charlie\"\n            ]\n    }\n}\n```\n\nAlright then, say we wish to remove Betty from the blacklist.\u003cbr /\u003e\nWe'd send a PATCH request, updating our `example` module's configuration.\u003cbr /\u003e\n\n``` bash title=\"Update Module Configuration (Admin Authentication)\"\ncurl --location --request PATCH 'http://localhost:3030/config/exampleModule/' \\\n     --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYzN2FiNzE3NjYxMzk4ZDUzNTBhZjhmYyIsImlhdCI6MTY2OTk5MjE1MSwiZXhwIjoxNjcwMDY0MTUxfQ.lgLnkrx_FDlUCsD5wNtXfMc3GKG41Eq7xN4BrnMznrw' \\\n     --header 'masterkey: M4ST3RK3Y' \\\n     --header 'Content-Type: application/json' \\\n     --data-raw '{\n         \"config\": {\n             \"illegalNames\": [\n                 \"Alex\",\n                 \"Charlie\"\n             ]\n         }\n}'\n```\n``` bash title=\"Response\"\n{\n    \"config\": {\n        \"active\": true,\n        \"defaultCookieCount\": 20,\n        \"illegalNames\": [\n            \"Alex\",\n            \"Charlie\"\n        ]\n    }\n}\n```\n\nOur configuration was updated successfully.\u003cbr /\u003e\nNotice how we only provided the configuration fields we wished to update.\n\nThis time around, if you were to perform another cookie retrieval request as Betty, the operation would be successful.\n\n### GraphQL\nYou may perform GraphQL queries and mutations directly through the GraphQL Playground,\nor through an GraphQL API testing tool of your choice.\n\nCheck the generated GraphQL documentation for details.\n\n### gRPC\nImport `src/service.proto` in a gRPC testing tool of your choice and specify `0.0.0.0:55152` as your server's address.\u003cbr /\u003e\nYou may then perform your gRPC requests.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkon14%2Fconduitmoduleexample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkon14%2Fconduitmoduleexample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkon14%2Fconduitmoduleexample/lists"}