{"id":25803165,"url":"https://github.com/flocasts/nestjs-google-pubsub-connector","last_synced_at":"2025-09-12T17:36:15.597Z","repository":{"id":39790771,"uuid":"357218811","full_name":"flocasts/nestjs-google-pubsub-connector","owner":"flocasts","description":"A NestJS Microservice for Google PubSub","archived":false,"fork":false,"pushed_at":"2023-07-05T18:18:29.000Z","size":1281,"stargazers_count":13,"open_issues_count":12,"forks_count":4,"subscribers_count":33,"default_branch":"develop","last_synced_at":"2024-04-21T22:38:36.312Z","etag":null,"topics":["gcp","nestjs","pubsub"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flocasts.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-04-12T14:10:59.000Z","updated_at":"2023-10-19T20:14:58.000Z","dependencies_parsed_at":"2023-07-17T09:46:06.434Z","dependency_job_id":null,"html_url":"https://github.com/flocasts/nestjs-google-pubsub-connector","commit_stats":{"total_commits":98,"total_committers":7,"mean_commits":14.0,"dds":"0.37755102040816324","last_synced_commit":"04626c1d6e83fd0d9d21d7e100627b5e21cfc19c"},"previous_names":["flocasts/nestjs-google-pubsub-microservice"],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flocasts%2Fnestjs-google-pubsub-connector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flocasts%2Fnestjs-google-pubsub-connector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flocasts%2Fnestjs-google-pubsub-connector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flocasts%2Fnestjs-google-pubsub-connector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flocasts","download_url":"https://codeload.github.com/flocasts/nestjs-google-pubsub-connector/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241040407,"owners_count":19898861,"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":["gcp","nestjs","pubsub"],"created_at":"2025-02-27T17:44:22.645Z","updated_at":"2025-02-27T17:44:23.179Z","avatar_url":"https://github.com/flocasts.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eNestJS Google Pubsub Connector\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@flosportsinc/nestjs-google-pubsub-connector\"\u003e\n    \u003cimg alt=\"npm latest version\" src=\"https://img.shields.io/npm/v/@flosportsinc/nestjs-google-pubsub-connector/latest.svg\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nThis package includes two pieces, a NestJS microservice strategy as well as a client proxy. Together this enables\neasy integration with Google PubSub in a NestJS-y way.\n\n## Features\n\n-   Seamlessly integrate your subscription listeners as controllers in the robust NestJS framework!\n-   Creates subscriptions on demand, with self-service naming strategies!\n-   A \"just-works\" approach means that zero configuration is needed out of the box, just insert the\n    strategy and let the framework do the rest.\n-   Oh-so Extensible:\n    -   Subscription naming strategies let you dynamically name subscriptions how _you_ want to!\n    -   Ack/nack strategies let you decouple your business logic from how you respond to messages!\n-   Decorators! Decorators!! Decorators!!!\n\n## Microservice Strategy\n\nThe server/transport strategy component is inserted as a strategy when creating a microservice, taking a\nfew configuration parameters, as well as an optional PubSub instance, like so:\n\n```typescript\nasync function bootstrap() {\n    const app: INestMicroservice = await NestFactory.createMicroservice\u003cMicroserviceOptions\u003e(\n        ExampleModule,\n        {\n            strategy: new GooglePubSubTransport({\n                createSubscriptions: true,\n                // The microservice will configure its own PubSub instance, but you're free to\n                // supply your own\n                // client: new PubSub()\n            }),\n        },\n    );\n\n    // It's also possible to connect as a hybrid app:\n    // const app = await NestFactory.create(HttpAppModule);\n    // const microservice = app.connectMicroservice({\n    //      strategy: new GooglePubSubTransport({\n    //          createSubscriptions: true,\n    //          // The microservice will configure its own PubSub instance, but you're free to\n    //          // supply your own\n    //          // client: new PubSub\n    //      }),\n    // });\n\n    return app.listen(() =\u003e {\n        console.log('example app started!');\n    });\n}\nbootstrap();\n```\n\nWith just the configuration above you can have working controllers responding to messages in minutes.\n\n### Decorators\n\nParameter decorators are one of the best ease-of-use features in NestJS, and this library offers a few\nthat will make parsing PubSub Messages easy, simple and fun:\n\n| Name                                 | Description                                                                                                                                                                                                                                                                                                                                                                  |\n| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| @GooglePubSubMessageHandler          | Takes a subscription name and optionally a topic name and creation parameters of subscription. A subscription will be created if it does not already exits **if**: a topic name is supplied **and** `createSubscriptions` was set to true when the microservice was created. The creation parameters are of type `CreateSubscriptionOptions` from the google pub/sub library |\n| @GooglePubSubMessageBody             | This will retrieve and `JSON.parse()` the body of the incoming message. You may optionally include a key and the corresponding value will be returned.                                                                                                                                                                                                                       |\n| @GooglePubSubMessageAttributes       | This will retrieve attributes of the incoming message. You may optionally include a key, and the corresponding value will be returned.                                                                                                                                                                                                                                       |\n| @GooglePubSubMessageDeliveryAttempts | This will return the number of delivery attempts for this message. Will only be incremented if the subscription has a Dead Letter Queue.                                                                                                                                                                                                                                     |\n| @GooglePubSubMessageId               | This will return the ID of the message.                                                                                                                                                                                                                                                                                                                                      |\n| @Ack                                 | This will return a function that will `ack` the incoming message. \u003c/br\u003e **N.B.** this will disable any auto-acking.                                                                                                                                                                                                                                                          |\n| @Nack                                | Same as above, but for nacking.                                                                                                                                                                                                                                                                                                                                              |\n\n### Subscription creation\n\nIf `createSubscriptions` is set as true on transporter setup, then the service will\nattempt to create a new subscription if the requested subscription for a handler is\nnot already present.The microservice takes a `subscriptionNamingStrategy` as an\nargument, which expects a class conforming to the `SubscriptionNamingStrategy`\ninterface. A basic strategy is included by default:\n\n```typescript\nimport { SubscriptionNamingStrategy } from '@flosports/nestjs-google-pubsub-microservice';\nimport { NamingDependencyTag, SubscriptionNameDependencies } from './interfaces';\n\nexport class BasicSubscriptionNamingStrategy implements SubscriptionNamingStrategy {\n    public generateSubscriptionName(deps: SubscriptionNameDependencies): string {\n        switch (deps._tag) {\n            case NamingDependencyTag.TOPIC_AND_SUBSCRIPTION_NAMES:\n            case NamingDependencyTag.SUBSCRIPTION_NAME_ONLY:\n                return deps.subscriptionName;\n            case NamingDependencyTag.TOPIC_NAME_ONLY:\n                return `${deps.topicName}-sub`;\n        }\n    }\n}\n```\n\nThe string returned from this strategy will be used as the name for the created subscription.\n\n### Acking and Nacking\n\nIn the interest of giving you, the user, the power over your own destiny this\nlibrary takes both a hands-off and \"just works\" approach to acking and nacking\nmessages. This is accomplished through \"strategies\" confirming to the `AckStrategy`,\n`NackStrategy` interfaces which are supplied at transport creation.\n\n#### Ack Strategies\n\nAck strategies are guaranteed to run after a handler completes successfully, and\nexpose functions for acking and nacking the message, as well as the messages\n`GooglePubSubContext`. The default is shown in the example below:\n\n```typescript\nimport { GooglePubSubContext } from '../ctx-host';\nimport { AckFunction, AckStrategy, NackFunction } from '../interfaces';\n\nexport class BasicAckStrategy implements AckStrategy {\n    public ack(ack: AckFunction, nack: NackFunction, ctx: GooglePubSubContext): Promise\u003cvoid\u003e {\n        if (ctx.getAutoAck()) {\n            ack();\n        }\n        return Promise.resolve();\n    }\n}\n```\n\nThe flow here is simple, if autoAck is set to true then this message will be acked\nand the function will return.\n\n#### Nack Strategies\n\nNack strategies are guaranteed to run if any error is thrown from the handler.\n\u003c/br\u003e\n_**N.B.** This will occur \\_after_ exception filters.\\_\n\u003c/br\u003e\nThe signature is the same as an ack strategies with the exception of the thrown Error\n(pun intended) being included as the first argument. The default is shown below:\n\n```typescript\nimport { GooglePubSubContext } from '../ctx-host';\nimport { AckFunction, NackFunction, NackStrategy } from '../interfaces';\n\nexport class BasicNackStrategy implements NackStrategy {\n    public nack(\n        error: Error,\n        ack: AckFunction,\n        nack: NackFunction,\n        ctx: GooglePubSubContext,\n    ): Promise\u003cvoid\u003e {\n        if (ctx.getAutoNack()) {\n            nack();\n        }\n        return Promise.resolve();\n    }\n}\n```\n\n#### No strategy/hybrid acking and nacking\n\nIn addition to using these strategies, the library also makes available ack and nack\nfunctions through decorators to the controller as well as from\nthe `GooglePubSubContext`. When ack or nack functions are\nretrieved from the context (either directly or through the\ndecorator) **the autoAck/autoNack methods will return false**,\ndisabling the basic strategies and optionally any strategies you\nshould choose to create. \u003c/br\u003e\n\n## Usage\n\n```typescript\n// src/main.ts\nimport { NestFactory } from '@nestjs/core';\nimport {\n    GooglePubSubTransport\n} from '@flosports/nestjs-google-pubsub-microservice';\nimport { TestModule } from './test.module';\n\nasync function bootstrap() {\n    const app = await NestFactory.createMicroservice(TestModule, {\n        strategy: new GooglePubSubTransport({\n            createSubscriptions: true,\n            // The microservice will configure its own PubSub instance, but you're free to\n            // supply your own\n            // client: new PubSub\n        }),\n    });\n    return app.listen(() =\u003e {\n        console.log('app started!');\n    });\n}\nbootstrap();\n\n// src/test.module.ts\nimport { Module } from \"@nestjs/common\";\nimport { TestController } from \"./test.controller\";\n\n@Module({\n    controllers: [TestController],\n})\nexport class TestModule {\n}\n\n// src/test.controller.ts\nimport { Controller } from '@nestjs/common';\nimport {\n    GooglePubSubMessageBody,\n    GooglePubSubMessageHandler\n} from '@flosports/nestjs-google-pubsub-microservice';\n@Controller()\nexport class TestController {\n    constructor(\n        private readonly diService: DiService;\n    ) { }\n    @GooglePubSubMessageHandler({\n        subscriptionName: 'my-existing-subscription',\n    })\n    public handler1(@GooglePubSubMessageBody() data: { foo: boolean }): void {\n        return this.diService.handleFoo(data);\n    }\n\n    @GooglePubSubMessageHandler({\n        subscriptionName: 'my-subscription-that-or-may-not-exist',\n        createOptions: {\n            enableMessageOrdering: true,\n        },\n        topicName: 'my-existing-topic'\n    })\n    public handler2(@GooglePubSubMessageBody('bar') bar:  boolean ): void {\n        return this.diService.handleBar(data);\n    }\n}\n```\n\n### One At A Time Processing\n\nThe library allows you to choose whether to handle your messages in parallel (the standard for PubSub) or serially. Simply enable the `oneAtATime` flag in the config option of your `@GooglePubSubMessageHandler` decorator. Once enabled, a new message will not be pulled until the handler returns or throws an error. Disabling or deleting the flag resets the behavior to default.\n\n**N.B.** This will only work within a single instance of your application. If running in a kubernetes cluster or other horizontally scaled environment, consider creating your application as a singleton.\n\n```typescript\n    @GooglePubSubMessageHandler({\n        subscriptionName: 'my-subscription-that-or-may-not-exist',\n        topicName: 'my-existing-topic'\n        oneAtATime: true //true for serial handling, false or blank for default\n    })\n    public handler2(@GooglePubSubMessageBody('bar') bar:  boolean ): void {\n        return this.diService.handleBar(data);\n    }\n\n```\n\n## Client Proxy\n\nThis library also provides a basic client proxy that wraps a PubSub instance.\n\nThis proxy supports:\n\n-   Publishing\n-   Topic/Subscription creation\n-   Topic/Subscription deletion\n\nYou can find a number of working examples in the [examples directory](examples/client).\n\n### Usage\n\n```typescript\nimport { ClientGooglePubSub } from '@flosports/nestjs-google-pubsub-microservice';\n\nconst msg = 'beam me up scotty';\n\nnew ClientGooglePubSub().publishToTopic('my-test-topic', Buffer.from(msg));\n```\n\n### Authentication\n\nIn keeping with the hand-off \"just works\" approach in this library, authentication is handled entirely\nby the underlying PubSub client. This means that the credentials pointed to by the `GOOGLE_APPLICATION_CREDENTIALS`\nwill be used, as well as emulator support if `PUBSUB_EMULATOR_HOST` is set. If you need a more advanced\nconfiguration, then both the transport strategy and the client proxy will take a PubSub client instance\nas a constructor parameter - you can simply build the client you need and then hand it off.\n\n### Examples\n\nA working example server can be found in the [examples directory](examples/server).\n\n#### Prerequisites for running the example server\n\nIn order to run the example server you must either:\n\n-   Have `GOOGLE_APPLICATION_CREDENTIALS` set in your environment, and pointed to a valid credentials, or\n-   Have a running PubSub emulator and have `PUBSUB_EMULATOR_HOST` set in your environment\n\nIn both cases you will need to create any topics present in the example server (or change them to\ntopics) that already exist.\n\n#### Running the example server\n\nTo run the server, simply invoke the provided `npm` script:\n\n```sh\nnpm run example:server\n```\n\nAssuming all prerequisites are met you should see something like the following:\n\n```sh\n\u003e @flosportsinc/nestjs-google-pubsub-connector@0.0.0-development example:server /Users/haroldwaters/repos/nestjs-google-pubsub-transport\n\u003e node --inspect -r ts-node/register examples/server/main.ts\n\nDebugger listening on ws://127.0.0.1:9229/d23772bb-0e6d-40f8-b47d-d0fc94c7c8c2\nFor help, see: https://nodejs.org/en/docs/inspector\n[Nest] 90792   - 04/17/2021, 7:04:02 PM   [NestFactory] Starting Nest application...\n[Nest] 90792   - 04/17/2021, 7:04:02 PM   [InstanceLoader] ExampleService dependencies initialized +28ms\n[Nest] 90792   - 04/17/2021, 7:04:02 PM   [InstanceLoader] ExampleModule dependencies initialized +0ms\n[Nest] 90792   - 04/17/2021, 7:04:02 PM   [NestMicroservice] Nest microservice successfully started +5ms\n[Nest] 90792   - 04/17/2021, 7:04:02 PM   [GooglePubSubTransport] Mapped {projects/flosports-174016/subscriptions/lee-christmas-notifications} handler\nexample app started!\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflocasts%2Fnestjs-google-pubsub-connector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflocasts%2Fnestjs-google-pubsub-connector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflocasts%2Fnestjs-google-pubsub-connector/lists"}