Skip to content

Controller Template

This template provides a standard structure for creating new controllers in the PRS system.

Usage Instructions

  1. Replace EntityName with your entity name
  2. Implement the methods below
  3. Add routes in the appropriate route file

Template Code

JavaScript
/**
 * Template for creating a new controller
 * 
 * Instructions:
 * 1. Replace EntityName with your entity name
 * 2. Implement the methods below
 * 3. Add routes in the appropriate route file
 */
class EntityNameController {
  constructor({ entityNameService, db, utils, entities, constants, clientErrors }) {
    this.entityNameService = entityNameService;
    this.db = db;
    this.utils = utils;
    this.entities = entities;
    this.constants = constants;
    this.clientErrors = clientErrors;
  }

  /**
   * Get all entities
   * 
   * @param {Object} request - Fastify request object
   * @param {Object} reply - Fastify reply object
   */
  async getAll(request, reply) {
    try {
      const { query } = request;
      const entities = await this.entityNameService.getAll(query);

      return reply.status(200).send(entities);
    } catch (error) {
      request.log.error({ error }, 'Error getting all entities');

      if (error.name === 'ValidationError') {
        return reply.status(400).send({
          success: false,
          message: 'Validation error',
          errors: error.details
        });
      }

      return reply.status(500).send({
        success: false,
        message: 'Internal server error'
      });
    }
  }

  /**
   * Get entity by ID
   * 
   * @param {Object} request - Fastify request object
   * @param {Object} reply - Fastify reply object
   */
  async getById(request, reply) {
    try {
      const { id } = request.params;
      const entity = await this.entityNameService.getById(id);

      if (!entity) {
        return reply.status(404).send({
          success: false,
          message: 'Entity not found'
        });
      }

      return reply.status(200).send(entity);
    } catch (error) {
      request.log.error({ error, id: request.params.id }, 'Error getting entity by ID');

      return reply.status(500).send({
        success: false,
        message: 'Internal server error'
      });
    }
  }

  /**
   * Create a new entity
   * 
   * @param {Object} request - Fastify request object
   * @param {Object} reply - Fastify reply object
   */
  async create(request, reply) {
    const transaction = await this.db.sequelize.transaction();

    try {
      const { userFromToken, body } = request;

      // Parse and validate request body
      const parsedBody = this.utils.parseDomain(
        this.entities.entityName.createEntityNameSchema,
        body
      );

      // Create entity
      const entity = await this.entityNameService.create({
        ...parsedBody,
        createdBy: userFromToken.id,
        transaction
      });

      await transaction.commit();

      return reply.status(201).send(entity);
    } catch (error) {
      await transaction.rollback();
      request.log.error({ error, body: request.body }, 'Error creating entity');

      if (error.name === 'ValidationError') {
        return reply.status(400).send({
          success: false,
          message: 'Validation error',
          errors: error.details
        });
      }

      return reply.status(500).send({
        success: false,
        message: 'Internal server error'
      });
    }
  }

  // Additional methods (update, delete) follow the same pattern
}

module.exports = EntityNameController;

Key Features

  1. Dependency Injection: Dependencies are injected through the constructor
  2. Error Handling: Consistent error handling pattern
  3. Transaction Management: Database transactions for write operations
  4. Validation: Input validation using domain schemas
  5. Logging: Structured logging for errors

Common Methods

  1. getAll: Retrieve all entities with optional filtering
  2. getById: Retrieve a single entity by ID
  3. create: Create a new entity
  4. update: Update an existing entity
  5. delete: Delete an entity

Best Practices

  1. Always use transactions for write operations
  2. Validate input using domain schemas
  3. Handle errors consistently
  4. Log errors with relevant context
  5. Return appropriate HTTP status codes