npm package: @platohq/nestjs-google-pubsub
Description: Google PubSub integration for NestJS
Latest version: 0.0.3

# @platohq/nestjs-google-pubsub

The NestJS module based on the official Google PubSub package

## How to install

```
npm install @platohq/nestjs-google-pubsub
```

or

```
yarn add @platohq/nestjs-google-pubsub
```

## How to use

You can use this package to integrate Google PubSub with NestJS for both producing or consuming messages.

### Producing messages

To add the ability to publish message to a given Google PubSub topic to any module, you need to do the following:

### Step 1. Import the `ClientsModule`

NestJS allows us to abstract the integration with a message broker pretty easily. To do that, you just need to import
the `ClientsModule` to your module, like this:

<!-- @formatter:off !-->
```ts
import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices'; // <-- Import statement
import { GooglePubSubClient } from '@platohq/nestjs-google-pubsub'; // <-- Import statement

@Module({
  imports: [{
    ClientsModule.register([{
      customClass: GooglePubSubClient,
      options: {
        projectId: 'your-project-id',
        // ... other options
        // You can check the list of available options on "Options" section of this document
      }
    }])
  }], // <-- Module metadata
  // ... everything else
})
export class YourModule {}
```
<!-- @formatter:on !-->

You can check a list with all available options on the [Options](#options) section. Also, you can
configure the `GooglePubSubClient` async using a dynamic configuration, like any other NestJS module.

### Step 2. Inject the Google PubSub client to your service

With the `ClientsModule` declared as a depedency, you can inject the `GooglePubSubClient` to your service, like
the following:

<!-- @formatter:off !-->
```ts
import { Inject, Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices'; // <-- ClientProxy interface
import { GooglePubSubClient } from '@platohq/nestjs-google-pubsub'; // <-- Injection token

@Injectable()
export class YourService {
  constructor(
    @Inject(GooglePubSubClient) // <-- Injection decorator
    private readonly client: ClientProxy, // <-- ClientProxy instance
  ) {
  }
  // ... everything else
}
```
<!-- @formatter:on !-->

With that in place, you can now use the `client` property to publish messages to a given topic.

### Step 3. Publish new messages

Right now we can only emit events (messages without response) to our topics, so to publish a message to a topic
named `test-topic`, you should do the following:

<!-- @formatter:off !-->
```ts
import { Inject, Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { GooglePubSubClient } from '@platohq/nestjs-google-pubsub'; // <-- Injection token

@Injectable()
export class YourService {
  constructor(
    @Inject(GooglePubSubClient)
    private readonly client: ClientProxy,
  ) {
  }
  public myCoolFunction(): void {
    this.client.emit('test-topic', "A clever message"); // <-- Emitting a message
  }
  // ... everything else
}
```
<!-- @formatter:on !-->

This will publish a message on topic named `test-topic` containing the following payload:

```json
{
  "data": "A clever message"
}
```

It is important to notice that everything passed as the second argument for the `emit` function will be serialized
inside a key named `data`. So, if your payload is an object, that object will be inside a key named `data` as well.

### Consuming messages

Creating a new consumer within this package is pretty straightforward. To do it, follow these steps:

### Step 1. Creates a new microservice

In your `main.ts` (or similar) file, add the following code to create a new NestJS Microservice:

```typescript
import {NestFactory} from "@nestjs/core";
import {GooglePubSubTransportStrategy} from "@platohq/nestjs-google-pubsub";

const app = await NestFactory.create(AppModule);

app.connectMicroservice({
  strategy: new GooglePubSubTransportStrategy({
    projectId: 'your-project-id',
    appName: 'your-app-name',
  }),
});
await app.startAllMicroservices();
```

### Step 2. Decorate your entrypoint

The first step is using the `EventPattern` decorator to define the topic you want to listen. Since our current
integration with Google Cloud PubSub only enables emitting events (without waiting for responses) you should always use
the `EventPattern` decorator, like the following:

<!-- @formatter:off !-->
```ts
import { Controller } from '@nestjs/common';
import { EventPattern } from '@nestjs/microservices'; // <-- Imports the decorator
import { GooglePubSubContext, SerializedMessage } from '@platohq/nestjs-google-pubsub'; // <-- Imports the context

@Controller()
export class MyController {
  @EventPattern('test-topic') // <-- Attached to the event listener
  public myConsumer(msg: SerializedMessage<unknown>, ctx: GooglePubSubContext): void {
    // ... your logic
  }

  // ... everything else
}
```
<!-- @formatter:on !-->

As you can imagine, with that decorator any incoming message on `test-topic` will be delivered to the `myConsumer`
method. Also, you can pass an optional argument to the `SerializedMessage` to increase type safety.

Finally, there is an optional second argument `ctx` which contains all the data provided by Google PubSub regarding that
method.

## Options

You can use the available options to customize how both your producer and consumer works. You can check the available
options below.

<!-- @formatter:off !-->
| **OPTION**                | **REQUIRED** | **TYPE**       | **DEFAULT**    | **DESCRIPTION**                                                      |
|---------------------------|--------------|----------------|----------------|----------------------------------------------------------------------|
| `projectId`               | Yes          | `null`         | `string`       | The Google Cloud project ID                                          |
| `autoCreateTopics`        | No           | `boolean`      | `true`         | Whether to create topics if they don't exist                         |
| `autoCreateSubscriptions` | No           | `boolean`      | `true`         | Whether to create subscriptions if they don't exist                  |
| `autoAck`                 | No           | `boolean`      | `true`         | Whether to automatically acknowledge messages                        |
| `appName`                 | No           | `string`       | `nestjs`       | The name of the application                                          |
| `signatureMarker`         | No           | `string`       | `__`           | The marker to separate the app name as a prefix on subscriptions     |
| `serializer`              | No           | `Serializer`   | `Serializer`   | The serializer to use to serialize new messages that we're sending   |
| `deserializer`            | No           | `Deserializer` | `Deserializer` | The deserializer to use to deserialize messages that we're receiving |
<!-- @formatter:on !-->

## Known limitations

- We currently only support emitting events (without a response). So, we still need to implement the request/reply.