Overview
The Hireflix API is built using GraphQL, a modern query language for APIs. Unlike REST, GraphQL uses a single endpoint where you describe exactly what data you need — no more, no less. In this tutorial, you’ll learn:- The difference between queries and mutations
- What union types are and how to use
__typename - How to interpret success and error responses
Queries vs. Mutations
In GraphQL, every request is either a query or a mutation.Query
Goal: Fetch data without making changes.Examples: Listing positions or fetching interview results.
Mutation
Goal: Make changes to data.Examples: Inviting a candidate, archiving a position, or deleting an interview.
Example: Query
Let’s look at this example queyr which fetches a list of open positions:query GetPositions- The keyword
querytells GraphQL you’re requesting data rather than changing it. GetPositionsis an operation name. You can think of it like a label for your query. It’s optional but useful for debugging or when running multiple queries.
- The keyword
positions- This is the root field being requested from the Hireflix API.
- Each GraphQL API defines a schema describing which root fields are available — in this case,
positionsreturns a list of Position objects (each representing a job).
{ id name archived }- Inside the curly braces
{ ... }you specify exactly which fields you want to retrieve for each position. You can only request fields defined by the schema for thePositiontype. - GraphQL only returns the fields you explicitly request: nothing more, nothing less. If you add
tagsorcreatedAt, they’ll appear in the response.
- Inside the curly braces
Response structure for a query:
The shape of the response matches the query:- The top-level
datakey always wraps your requested fields. - Each object under
positionscontains exactly the fields you asked for — no hidden data or unused properties.
Example: Mutation
Invite a new candidate to an interview:mutation InviteCandidateToInterview- The keyword
mutationtells GraphQL you want to change data. For example, creating, updating, or deleting something. InviteCandidateToInterviewis the operation name (optional, but helpful for identifying the mutation later).
- The keyword
inviteCandidateToInterview(...)- This is the mutation field. Think of it as a function exposed by the API.
- The parentheses
( ... )contain the arguments the mutation expects.- Here, it accepts a single argument named
input, which bundles all the required parameters like email, firstName, and lastName to invite a candidate. - The way the arguments are structured is determined by the mutation field. Each mutation has a different set of input parameters.
- Here, it accepts a single argument named
- Selection set: (the
{ ... }after the mutation)- This part defines what data you want back from the mutation. Even when you’re modifying data, you can decide what to return, just like a query. In this case, we want to receive the interview
IDand the interviewurlso we can use it in our frontend.
- This part defines what data you want back from the mutation. Even when you’re modifying data, you can decide what to return, just like a query. In this case, we want to receive the interview
Example: Mutation With Union Type
Some mutations use the Union Type notation (... on Type), which GraphQL provides. It allows you to better interpret the returned object, which improves error handling.
InterviewType— success (interview created).InterviewAlreadyExistsInPositionError— candidate already invited.ExceededInvitesThisPeriodError— plan limit reached.
__typename field. This is why many Hireflix queries include it. It helps you detect whether the operation succeeded or failed. In GraphQL, even when a mutation fails, the API still returns an HTTP 200 response. Errors are instead reported in one of two ways:
- Through an
errorsarray (for most operations), or - As an error object identified by its
__typename(for union-type mutations).
Summary
- Queries → Fetch data.
- Mutations → Modify data.
- Union Types → Let a single mutation return either a success or error type.
__typename→ Use this field to determine the result type at runtime.

