A progressive Node.js framework for building efficient and scalable server-side applications, heavily inspired by Angular.
Azure Database (Table Storage and more) module for Nest framework (node.js)
Learn how to get started with Azure table storage for NestJS
- Create a Storage account and resource (read more)
- For Table Storage, In the Azure Portal, go to Dashboard > Storage > your-storage-account.
- Note down the "Storage account name" and "Connection string" obtained at Access keys under Settings tab.
$ npm i --save @nestjs/azure-database
- Create or update your existing
.env
file with the following content:
AZURE_STORAGE_CONNECTION_STRING=
-
IMPORTANT: Make sure to add your
.env
file to your .gitignore! The.env
file MUST NOT be versioned on Git. -
Make sure to include the following call to your main file:
if (process.env.NODE_ENV !== 'production') require('dotenv').config();
This line must be added before any other imports!
- Create a new feature module, eg. with the nest CLI:
$ nest generate module contact
- Create a Data Transfer Object (DTO) inside a file named
contact.dto.ts
:
export class ContactDTO {
name: string;
message: string;
}
- Create a file called
contact.entity.ts
and describe the entity model using the provided decorators:
-
@EntityPartitionKey(value: string)
: Represents thePartitionKey
of the entity (required). -
@EntityRowKey(value: string)
: Represents theRowKey
of the entity (required). -
@EntityInt32(value?: string)
: For signed 32-bit integer values. -
@EntityInt64(value?: string)
: For signed 64-bit integer values. -
@EntityBinary(value?: string)
: For binary (blob) data. -
@EntityBoolean(value?: string)
: Fortrue
orfalse
values. -
@EntityString(value?: string)
: For character data. -
@EntityDouble(value?: string)
: For floating point numbers with 15 digit precision. -
@EntityDateTime(value?: string)
: For time of day.
For instance, the shape of the following entity:
import { EntityPartitionKey, EntityRowKey, EntityString } from '@nestjs/azure-database';
@EntityPartitionKey('ContactID')
@EntityRowKey('ContactName')
export class Contact {
@EntityString() name: string;
@EntityString() message: string;
}
Will be automatically converted to:
{
"PartitionKey": { "_": "ContactID", "$": "Edm.String" },
"RowKey": { "_": "ContactName", "$": "Edm.String" },
"name": { "_": undefined, "$": "Edm.String" },
"message": { "_": undefined, "$": "Edm.String" }
}
Note: The provided entity type annotations represent the Entity Data Model types.
- Import the
AzureTableStorageModule
inside your Nest feature modulecontact.module.ts
:
import { Module } from '@nestjs/common';
import { AzureTableStorageModule } from '@nestjs/azure-database';
import { ContactController } from './contact.controller';
import { ContactService } from './contact.service';
import { Contact } from './contact.entity';
@Module({
imports: [AzureTableStorageModule.forFeature(Contact)],
providers: [ContactService],
controllers: [ContactController],
})
export class ContactModule {}
You can optionally pass in the following arguments:
AzureTableStorageModule.forFeature(Contact, {
table: 'AnotherTableName',
createTableIfNotExists: true,
})
table: string
: The name of the table. If not provided, the name of theContact
entity will be used as a table namecreateTableIfNotExists: boolean
: Whether to automatically create the table if it doesn't exists or not:- If
true
the table will be created during the startup of the app. - If
false
the table will not be created. You will have to create the table by yourself before querying it!
- If
- Create a service that will abstract the CRUD operations:
$ nest generate service contact
- Use the
@InjectRepository(Contact)
to get an instance of the AzureRepository
for the entity definition created earlier:
import { Injectable } from '@nestjs/common';
import { Repository, InjectRepository } from '@nestjs/azure-database';
import { Contact } from './contact.entity';
@Injectable()
export class ContactService {
constructor(
@InjectRepository(Contact)
private readonly contactRepository: Repository<Contact>) {}
}
The AzureTableStorageRepository
provides a couple of public APIs and Interfaces for managing various CRUD operations:
create(entity: T, rowKeyValue?: string): Promise<T>
: creates a new entity.
@Post()
async create(contact: Contact, rowKeyValue: string): Promise<Contact> {
//if rowKeyValue is null, rowKeyValue will generate a UUID
return this.contactRepository.create(contact, rowKeyValue)
}
find(rowKey: string, entity: Partial<T>): Promise<T>
: finds one entity using its RowKey
.
@Get(':rowKey')
async getContact(@Param('rowKey') rowKey) {
try {
return await this.contactService.find(rowKey, new Contact());
} catch (error) {
// Entity not found
throw new UnprocessableEntityException(error);
}
}
findAll(tableQuery?: azure.TableQuery, currentToken?: azure.TableService.TableContinuationToken): Promise<AzureTableStorageResultList<T>>
: finds all entities that match the given query (return all entities if no query provided).
@Get()
async getAllContacts() {
return await this.contactService.findAll();
}
update(rowKey: string, entity: Partial<T>): Promise<T>
: Updates an entity. It does a partial update.
@Put(':rowKey')
async saveContact(@Param('rowKey') rowKey, @Body() contactData: ContactDTO) {
try {
const contactEntity = new Contact();
// Disclaimer: Assign only the properties you are expecting!
Object.assign(contactEntity, contactData);
return await this.contactService.update(rowKey, contactEntity);
} catch (error) {
throw new UnprocessableEntityException(error);
}
}
@Patch(':rowKey')
async updateContactDetails(@Param('rowKey') rowKey, @Body() contactData: Partial<ContactDTO>) {
try {
const contactEntity = new Contact();
// Disclaimer: Assign only the properties you are expecting!
Object.assign(contactEntity, contactData);
return await this.contactService.update(rowKey, contactEntity);
} catch (error) {
throw new UnprocessableEntityException(error);
}
}
delete(rowKey: string, entity: T): Promise<AzureTableStorageResponse>
: Removes an entity from the database.
@Delete(':rowKey')
async deleteDelete(@Param('rowKey') rowKey) {
try {
const response = await this.contactService.delete(rowKey, new Contact());
if (response.statusCode === 204) {
return null;
} else {
throw new UnprocessableEntityException(response);
}
} catch (error) {
throw new UnprocessableEntityException(error);
}
}
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please read more here.
- Author - Wassim Chegham
- Website - https://wassim.dev
- Twitter - @manekinekko
Nest is MIT licensed.