Skip to main content

Getting Started

1. Define a data type

Services are typed against an OPRA ComplexType. Decorate your class with @ComplexType and annotate each field:

import { ComplexType, ApiField } from '@opra/common';

@ComplexType()
export class Product {
@ApiField() _id: string;
@ApiField() name: string;
@ApiField() category: string;
@ApiField() price: number;
@ApiField() inStock: boolean;
}

2. Create a service class

Extend ElasticCollectionService and pass the data type to the constructor:

import { ElasticCollectionService } from '@opra/elastic';
import { Product } from '../models/product.js';

export class ProductsService extends ElasticCollectionService<Product> {
constructor() {
super(Product);
}
}

The index name defaults to the data type name ('Product'). Override it when needed:

super(Product, { indexName: 'products' });

3. Connect a client

Pass an @elastic/elasticsearch Client instance through the constructor options:

import { Client } from '@elastic/elasticsearch';

export class ProductsService extends ElasticCollectionService<Product> {
constructor(readonly client: Client) {
super(Product, { client });
}
}

4. Use for(context) per request

Every service exposes a for(context, overwriteProperties?) method that returns a scoped copy of the service bound to the current execution context. Call it at the start of every request handler:

async getProduct(ctx: HttpContext) {
return this.productsService.for(ctx).get(ctx.pathParams.id);
}

for() is cheap — it does not create a new class instance, only a shallow proxy that inherits all configuration from the parent.


5. NestJS integration

import { Injectable } from '@nestjs/common';
import { Client } from '@elastic/elasticsearch';

@Injectable()
export class ProductsService extends ElasticCollectionService<Product> {
constructor(readonly client: Client) {
super(Product, { client });
}
}

Inject into a controller:

@Injectable()
export class ProductsController {
constructor(private readonly products: ProductsService) {}

@HttpOperation.Entity.Get({ type: Product })
async get(ctx: HttpContext) {
return this.products.for(ctx).get(ctx.pathParams.id);
}
}

Next steps