• Español
  • Diseño de inputs para queries y mutations

    Este estándar define la estructura de inputs de todas las queries y mutations de nuestras APIs GraphQL: un único input object con filtros, búsqueda, ordenamiento y paginación consistentes.

    El problema

    Sin una estructura estándar, cada query inventa su propia forma de pasar parámetros y la API se vuelve inconsistente, difícil de usar y difícil de mantener a medida que crece. Los síntomas típicos:

    • Convenciones de parámetros inconsistentes entre queries.
    • Filtros y ordenamiento que no escalan a casos complejos.
    • Opciones difíciles de descubrir.
    • Manejo de versiones complicado.
    • Estructura de entrada difícil de documentar.

    La solución: un input object estandarizado

    Todas las queries y mutations envuelven sus parámetros en un único argumento input con una estructura consistente:

    1. Input object raíz: todos los parámetros se pasan por un único argumento input.
    2. Identificadores: los IDs del recurso (por ejemplo organizationId, userId) van como propiedades directas del input.
    3. Objeto filter: objeto anidado para filtrar, con operadores consistentes.
    4. Objeto search: parámetros de búsqueda estructurados.
    5. Arreglo sort: mecanismo estándar de ordenamiento.
    6. Objeto pagination: controles de paginación consistentes.

    Requisitos obligatorios

    Todo diseño nuevo de schema para queries y mutations cumple estos requisitos:

    1. Input único: usa siempre un único parámetro llamado input que recibe un input object.
    2. Naming consistente: todo input type termina con el sufijo Input (por ejemplo, ATSListJobApplicantInput).
    3. Operadores estándar: usa sufijos de operador consistentes al filtrar:
      • _eq, _neq para igualdad
      • _gt, _gte, _lt, _lte para comparaciones
      • _in, _nin para inclusión o exclusión en arreglos
    4. Paginación: toda query de listado soporta la paginación estándar.
    5. Ordenamiento: toda query de listado soporta ordenar por sus campos relevantes.
    6. Búsqueda: donde aplique, implementa el patrón estándar de búsqueda.
    7. Identificadores: los identificadores de la entidad van siempre como campos de primer nivel del input object.
    8. Documentación: todo campo del input lleva su descripción.

    Definición del schema

    # Base input structure for all queries/mutations
    input BaseQueryInput {
      # Optional filter object
      filter: FilterInput
      # Optional search parameters
      search: SearchInput
      # Optional sorting parameters
      sort: [SortInput!]
      # Optional pagination parameters
      pagination: CursorPaginationInput | OffsetPaginationInput
    }
    
    # Common filtering patterns
    input FilterInput {
      # Fields vary based on entity but operator patterns remain consistent
      # Examples of common operators:
      # _eq: Equals
      # _neq: Not equals
      # _gt: Greater than
      # _gte: Greater than or equal
      # _lt: Less than
      # _lte: Less than or equal
      # _in: Included in array
      # _nin: Not included in array
    }
    
    # Search functionality
    input SearchInput {
      # Search query string
      query: String!
      # Optional fields to search within
      fields: [String!]
    }
    
    # Sorting control
    input SortInput {
      # Field to sort by
      field: String!
      # Sort direction
      direction: SortDirection!
    }
    
    # Sort direction enum
    enum SortDirection {
      ASC
      DESC
    }
    
    # Pagination control
    input CursorPaginationInput {
      after: String
      first: Int
    }
    
    input OffsetPaginationInput {
      # Page number (1-based)
      page: Int
      # Items per page
      pageSize: Int
    }
    
    # Entity-specific input extending base input
    input ATSListJobApplicantInput {
      # Required organization ID
      organizationId: ID!
      # Optional job ID
      jobId: ID
      # Filtering options specific to job applicants
      filter: JobApplicantFilterInput
      # Standard search, sort, pagination
      search: SearchInput
      sort: [SortInput!]
      pagination: CursorPaginationInput | OffsetPaginationInput
    }
    
    # Entity-specific filter
    input JobApplicantFilterInput {
      # Applicant status filtering
      status_in: [ApplicantStatus!]
      # Date range filtering
      appliedDate_gte: DateTime
      appliedDate_lte: DateTime
      # Custom filters
      customField_eq: String
    }

    Ejemplos de uso

    Listar postulantes de una vacante

    query AtsAdminApplicantListPageGetApplicantList($input: ATSListJobApplicantInput!) {
      ats_recruitment {
        list_job_applicant_admin(input: $input) {
          id
          name
          email
          status
          appliedDate
        }
      }
    }

    Con estas variables:

    {
      "input": {
        "centralized_organization_id": "1",
        "filter": {
          "status_in": ["APPLIED", "SCREENING"],
          "applied_date_gte": "2025-01-01T00:00:00Z"
        },
        "search": {
          "query": "developer",
          "fields": ["name", "resume"]
        },
        "sort": [{ "field": "applied_date", "direction": "DESC" }],
        "pagination": {
          "page": 1,
          "pageSize": 20
        }
      }
    }

    Búsqueda de productos

    query ProductSearch($input: ProductSearchInput!) {
      products {
        search(input: $input) {
          id
          title
          price
          category
          brand
        }
      }
    }

    Con estas variables:

    {
      "input": {
        "centralized_organization_id": "1",
        "filter": {
          "category": "ELECTRONICS",
          "price_gte": 1000,
          "brand_in": ["BrandA", "BrandB"]
        },
        "search": {
          "query": "laptop",
          "fields": ["title", "description"]
        },
        "sort": [{ "field": "price", "direction": "ASC" }],
        "pagination": {
          "page": 1,
          "pageSize": 50
        }
      }
    }

    Ventajas y desventajas

    El patrón gana consistencia a cambio de verbosidad.

    Ventajas:

    • Consistencia: estructura uniforme en todas las queries y mutations.
    • Escalabilidad: se extiende con nuevas opciones de filtro sin breaking changes.
    • Descubrimiento: los patrones claros hacen más fácil deducir qué opciones existen.
    • Mantenibilidad: los patrones consistentes simplifican el mantenimiento de la API.
    • Documentación: es más fácil documentar y entender el formato de entrada esperado.
    • Evolución: la API evoluciona gradualmente sin romper a los clientes.
    • Menos boilerplate: la paginación y el ordenamiento quedan estandarizados.

    Desventajas:

    • Verbosidad: más verboso que pasar parámetros simples en queries simples.
    • Curva de aprendizaje: quien llega al equipo necesita aprender las convenciones del patrón.
    • Complejidad de implementación: el backend necesita más código para manejar la estructura flexible.
    • Performance: el filtrado genérico puede ser menos performante que una query especializada.
    • Tamaño del schema: la documentación del schema de GraphQL puede crecer.