Skip to main content
POST
/
specialities
Create Specialty
curl --request POST \
  --url https://api.example.com/specialities \
  --header 'Content-Type: application/json' \
  --data '
{
  "name": "<string>",
  "state": "<string>"
}
'
{
  "speciality": {
    "id": 123,
    "name": "<string>",
    "state": "<string>",
    "createdAt": "<string>",
    "updatedAt": "<string>"
  }
}

Overview

Creates a new medical specialty in the system. Only administrators can create specialties.

Authentication & Authorization

This endpoint requires both authentication AND administrator privileges.
Required: JWT token from an admin user Middleware chain:
  1. validatorJWT - Validates JWT token (backend/middlewares/validatorJWT.ts)
  2. isAdmin - Verifies user has admin role (backend/middlewares/validatorAdmin.ts)
  3. Validation checks:
    • check("name", "El nombre es obligatorio").not().isEmpty() - Name is required
    • check("name").custom(existNameSpeciality) - Name must be unique
  4. collectionErrors - Handles validation errors
Authorization: Admin role required. Non-admin users will receive a 401 or 403 error.

Endpoint

POST /specialities
Implementation: backend/controllers/speciality.ts:7

Request Body

name
string
required
The name of the medical specialty. Must be unique across the system.Validation:
  • Cannot be empty
  • Must be unique (validated by existNameSpeciality helper)
  • Case-sensitive uniqueness check
Examples:
  • "Cardiología"
  • "Pediatría"
  • "Medicina General"
  • "Traumatología"
Validation source: backend/routes/speciality.ts:33-34
state
string
The initial state of the specialty. If not provided, defaults to “Activa”.Allowed values:
  • "Activa" - Active specialty (default)
  • "Inactiva" - Inactive specialty
Default: "Activa"Note: While this field is optional in the request body, it’s defined as allowNull: false in the model, so Sequelize will use the default value.

Request Examples

curl -X POST "http://localhost:3000/specialities" \
  -H "Authorization: Bearer ADMIN_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Cardiología"
  }'

Response

speciality
object
required
The newly created specialty object.

Response Examples

{
  "speciality": {
    "id": 5,
    "name": "Cardiología",
    "state": "Activa",
    "createdAt": "2024-03-11T15:30:00.000Z",
    "updatedAt": "2024-03-11T15:30:00.000Z"
  }
}

Status Codes

Status CodeDescription
201Created - Specialty successfully created
400Bad Request - Validation error (missing name or duplicate)
401Unauthorized - Invalid or missing JWT token
403Forbidden - User is not an administrator
500Server Error - Database or internal error

Implementation Details

Controller Logic

The create endpoint uses Sequelize’s create method:
export const createSpeciality = async (req: Request, res: Response) => {
  const data = req.body;

  try {
    const speciality = await Speciality.create(data)

    res.status(201).json({
      speciality
    })
  } catch (error) {
    console.log(error)
    res.status(500).json({
      msg: "Error del servidor"
    })
  }
}
Source: backend/controllers/speciality.ts:7-26

Validation Chain

Validations are defined in the route:
router.post('/',
  [
    validatorJWT,
    isAdmin,
    check("name", "El nombre es obligatorio").not().isEmpty(),
    check("name").custom(existNameSpeciality),
    collectionErrors
  ],
  createSpeciality
)
Source: backend/routes/speciality.ts:29-38

Uniqueness Check

The existNameSpeciality helper validates that the name doesn’t already exist:
// Helper location: backend/helpers/validationsDB.ts
export const existNameSpeciality = async (name: string) => {
  const speciality = await Speciality.findOne({ where: { name } });
  
  if (speciality) {
    throw new Error('El nombre de la especialidad ya existe');
  }
}

Admin Authorization

The isAdmin middleware verifies the user has admin privileges: Source: backend/middlewares/validatorAdmin.ts

State Management

States are enforced at the database level using Sequelize ENUM:
state: {
  type: DataTypes.ENUM(...Object.values(STATES_SPECIALITIES)),
  allowNull: false,
  defaultValue: STATES_SPECIALITIES.active  // "Activa"
}
Source: backend/models/speciality.ts:27-31

Common Use Cases

Basic specialty creation

const createSpecialty = async (name: string) => {
  const response = await fetch('/specialities', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${adminToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ name })
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.msg || 'Failed to create specialty');
  }

  return await response.json();
};

Create with error handling

try {
  const { speciality } = await createSpecialty('Cardiología');
  console.log(`Created specialty with ID: ${speciality.id}`);
} catch (error) {
  if (error.message.includes('ya existe')) {
    console.error('A specialty with this name already exists');
  } else {
    console.error('Failed to create specialty:', error.message);
  }
}

Bulk creation with validation

const specialtyNames = ['Cardiología', 'Pediatría', 'Neurología'];

const results = await Promise.allSettled(
  specialtyNames.map(name => 
    fetch('/specialities', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${adminToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ name })
    })
  )
);

const created = results.filter(r => r.status === 'fulfilled');
const failed = results.filter(r => r.status === 'rejected');

console.log(`Created: ${created.length}, Failed: ${failed.length}`);

Notes

Only users with admin role can create specialties. Attempting to call this endpoint without admin privileges will result in a 403 Forbidden error.
Specialty names are case-sensitive and must be unique. “Cardiología” and “cardiología” would be considered different specialties.

Important Considerations

  • The state field defaults to “Activa” if not provided
  • Specialty names cannot be empty strings or whitespace
  • The uniqueness constraint is enforced at the database level
  • Admin authentication is required - the isAdmin middleware checks the user’s role
  • Validation errors return 400 with detailed error information
  • Database errors (including duplicate key errors) may return 500

Build docs developers (and LLMs) love