skip to content

Why are GraphQL field names like getEmployee or payslipsFromHrisV2 discouraged?

level: middleimportance: should knowfreq 48%

answer

  1. A field is not a call
  2. The operation type already said read
  3. Names become the client's response keys
  4. Backends change; the name stays
  5. A verb on Query can hide a write

basics

~20 s

A field names the data it yields, not the call behind it. The operation type already says the request is a read, so get is noise, and a name carrying the backing system becomes a lie the day that system is replaced.

solid answer

~40 s

Two problems, one root: the name describes the implementation instead of the data. The `get` prefix is redundant because the document already declares `query` or `mutation`, and it reads badly once nested - `getEmployee { getManager { getDepartment } }` looks like four calls rather than one traversal. Worse, field names are not internal: absent an alias, the field name is the response key, so the noise lands in every client's data shape, cache keys and generated types. A name like `payslipsFromHrisV2` bakes in a backend that a payroll graph will outlive; when it is replaced the field either lies or must be renamed, and renaming is what shipped clients cannot absorb. Name for what is returned and put the criteria in arguments: `employee(id: ID!)`, `payslips(payRunId: ID!)`, `Employee.manager`.

code

graphql · 10 lines
graphql
type Query {
  getEmployee(id: ID!): Employee
  fetchPayslipsFromHrisV2(employeeId: ID!): [Payslip!]!
  approveTimesheet(id: ID!): Boolean!
}

type Employee {
  getManager: Employee
  payslipArray: [Payslip!]!
}

go deeper

for a junior

Know the plain rule and one reason for it: name a field for the data it returns, because the operation already says whether the request reads or writes, and the field name shows up as a key in the response body.

for a middle

Be ready to walk through the consequences: response keys, nested readability, generated property names, and what happens to a field named after a backing system once that system is replaced.

for a senior

Show that you weigh naming against change cost. Argue why a field name is contract surface that outlives the backend, and be able to talk through a write mistakenly exposed on the read root and who stopped looking at it as a result.

for a principal

Own the standard rather than the individual name: a written convention that fields are nouns, criteria are arguments and no name mentions a backing system, enforced at review time, because after publication the only correction is a rename.

## A field is a property, not a procedure The unit a GraphQL schema exposes is a field on a type, and a client reaches it by selecting it inside a selection set. Read that way, a field name is best understood as the name of the data it yields, not the name of the operation that yields it. `Employee.manager` names a person. `Employee.getManager` names a subroutine, and it is the only clue in the schema that whoever wrote it was thinking about the call they were wrapping rather than the graph they were exposing. The redundancy is the easiest half of the argument to make in an interview. A document already declares its operation type: `query` or `mutation`. Every field reachable from the query root is a read by construction, so the `get` prefix restates in each field name something the document already says once at the top. ## Names are the client's data shape The stronger half of the argument is that field names are not internal. The response object uses the response key for each selected field, and absent an alias that key is the field name itself. So a payroll graph with `Query.getEmployee` and `Employee.getManager` does not merely read awkwardly in the schema; it produces `data.getEmployee.getManager` in every response body, and that path is what application code destructures, what a normalized client cache stores under, and what a typed generator turns into a property name. The noise is copied into every consumer. Nesting compounds it. `employee { manager { department { costCentre } } }` reads as a path through data. `getEmployee { getManager { getDepartment { getCostCentre } } }` reads as four function calls and hides the fact that it is one traversal. ## A name that encodes the backing call ages badly `payslipsFromHrisV2` or `employeesFromLegacyLedger` is a different failure with the same root: the name describes the implementation rather than the data. Schemas outlive their backends. When the payroll system behind that field is replaced — and on a benefits and payroll graph it will be, because those systems are bought and migrated on a cycle of a few years — the field either keeps a name that is now a lie, or it has to be renamed. Renaming is the expensive path: shipped mobile builds, saved documents and generated client code all carry the old name, so the name outlives the system it was named after and the mistake is paid for continuously. The same reasoning rules out putting the return type in the name. `employeeList`, `payslipArray`, `planMap` all restate what the schema already declares in the field's type, in tooling that already shows it, and all three become wrong the day the field's shape changes. ## The read/write hazard There is a sharper version of the verb problem. A field named for an action tends to *be* an action. A payroll graph that exposes `Query.approveTimesheet` has put a write on the read root. GraphQL describes a query operation as a read-only fetch and a mutation as a write followed by a fetch, and only mutation fields at the top level of an operation are given serial execution — but nothing in the language enforces read-only-ness, and a server cannot detect that a resolver wrote something. What actually goes wrong is human and procedural: the reviewers, the write-path guards and the audit tooling that all watch mutation fields never look at query fields. In one such graph the approval was executed on the read path and the permission check that should have gated it ran too late, in a downstream consumer, long after the timesheets had been approved. The name is what routed the field away from everyone who would have caught it. ## What to name instead Name the field for what it returns, and put the criteria in arguments: `employee(id: ID!): Employee`, `payslips(payRunId: ID!): [Payslip!]!`, `benefitPlans(effectiveOn: Date!): [BenefitPlan!]!`. Use a plural noun for a list. Keep computed reads nouns too — `projectedNetPay(payRunId: ID!)` is a calculation, but what the client wants is the number, so the number is what the field is called. Verbs do have a home. A mutation is named for the business action it performs, and that convention — along with the input-argument and payload shapes that go with it — is the neighbouring concern, not this one. The rule that survives is narrower and easier to apply: on any field reachable from the query root, or on any object type, a verb in the name is a signal to stop and ask what is really being modelled. ## How to argue it in an interview Interviewers read naming as design taste, and the answer that lands is not "because the style guide says so". It is that field names are part of the contract, appear in every response body, outlive the systems behind them, and are expensive to change — so a name should describe the data, be stable under a backend swap, and not disguise a write as a read.

  • Is there a read field where a verb is genuinely the right name?
    Rarely. Computed reads are still named for their result - `projectedNetPay(payRunId: ID!)` rather than `calculateNetPay` - because the client wants the number, not the calculation. Verbs belong on mutations, where the convention is to name the field for the business action; that convention and the argument and payload shapes around it are the neighbouring concern, not this one.
  • Should a field name state its return type, as in employeeList or payslipArray?
    No. The type is already declared on the field and shown by every tool that reads the schema, so the suffix only restates it - and it becomes wrong the moment the shape changes, for instance when a plain list is replaced by a paged shape. A plural noun already communicates that several items come back.
  • A shipped field is named payslipsFromHrisV2 and that system is being retired. What does leaving the name actually cost?
    Every consumer has bound to it as a response key and a generated property, and every reader of the schema now infers a backend that no longer exists. The data is fine; the contract is misleading, and the misleading name is the cheapest of the two options, because correcting it means every client that selects the field has to change.

saying these in an interview costs you the question

  • Says get- prefixes make the schema clearer for newcomers
  • Thinks field names stay internal to the server
  • Names fields after the service or table behind them
  • Assumes renaming a shipped field is a cheap edit
  • Treats any Query field as safe because queries are reads
  • Puts the return type into the field name

context