Cypress API Testing: How to Test REST and GraphQL Endpoints with cy.request()

Cypress provides built-in API testing capabilities through the cy.request() command, which executes HTTP requests directly from the Node.js runtime to test REST, GraphQL, and other HTTP-based APIs without loading a browser page.

Cypress is primarily known as an end-to-end testing framework, but it also includes powerful API testing features that allow you to validate backend services directly. The cy.request() command serves as a fully-featured HTTP client that operates outside the browser's security sandbox, making it ideal for testing REST endpoints, GraphQL queries, and microservices. According to the cypress-io/cypress source code, this functionality is deeply integrated into the core driver package, providing automatic cookie handling, redirect following, and retry logic that mirrors browser behavior.

How cy.request() Enables Cypress API Testing

Unlike browser-based fetch or XMLHttpRequest, cy.request() runs inside the Cypress driver runtime. This architecture allows it to bypass Cross-Origin Resource Sharing (CORS) restrictions and execute arbitrary HTTP methods including GET, POST, PUT, DELETE, PATCH, OPTIONS, and HEAD.

The Network Layer Implementation

The implementation in packages/driver/src/cypress/network_utils.ts handles the low-level Node.js HTTP/HTTPS request construction, applying Cypress-specific defaults such as baseUrl resolution, automatic cookie persistence, and configurable retry logic.

Request Configuration Options

cy.request() accepts a configuration object that supports:

  • Request bodies as strings, JavaScript objects, FormData, or binary buffers
  • Custom headers and authentication objects
  • Query parameters and timeout values
  • failOnStatusCode option to prevent tests from failing on non-2xx responses (enabling negative testing)

Core Implementation Files

The API testing capabilities rely on three key modules within the packages/driver directory:

Network Utilities (network_utils.ts)

The packages/driver/src/cypress/network_utils.ts file contains the core HTTP implementation. This module builds the actual Node.js HTTP/HTTPS request, manages connection pooling, and implements the retry-ability logic that integrates with Cypress's automatic retry system.

Error Handling and Validation (error_messages.ts)

The packages/driver/src/cypress/error_messages.ts file centralizes validation logic for cy.request(). It defines specific error messages for missing URLs, invalid HTTP methods, and malformed headers, providing clear documentation links to guide developers.

Proxy Logging (proxy-logging.ts)

Visibility into API calls comes from packages/driver/src/cypress/proxy-logging.ts, which emits log entries displayed in the Cypress Command Log. This allows developers to inspect request details, response times, and status codes directly in the test runner UI.

Cypress API Testing Examples

The following patterns demonstrate how to test REST endpoints using cy.request():

Simple GET Request

Fetch a JSON endpoint and assert on specific properties in the response body:

cy.request('https://jsonplaceholder.typicode.com/todos/1')
  .its('body')
  .should('include', { id: 1, completed: false })

POST with JSON Body and Custom Headers

Send data to an endpoint with custom content-type headers:

cy.request({
  method: 'POST',
  url: '/api/users',
  headers: { 'Content-Type': 'application/json' },
  body: { name: 'Jane Doe', email: 'jane@example.com' },
})
  .its('status')
  .should('eq', 201)

Negative Testing with Error Handling

Test error scenarios by preventing automatic failure on non-2xx status codes:

cy.request({
  url: '/auth/login',
  method: 'POST',
  body: { username: 'bad', password: 'wrong' },
  failOnStatusCode: false,
}).its('status')
  .should('eq', 401)

Persisting API Responses as Fixtures

Capture API responses for reuse across test suites:

cy.request('/api/products')
  .its('body')
  .then((products) => {
    cy.writeFile('cypress/fixtures/products.json', products)
  })

Combining with cy.intercept for Request Validation

Verify request payloads by spying on network traffic:

cy.intercept('POST', '/api/orders', (req) => {
  expect(req.body).to.have.property('productId')
}).as('order')

cy.request({
  method: 'POST',
  url: '/api/orders',
  body: { productId: 42, qty: 3 },
})

cy.wait('@order')

Summary

  • cy.request() provides a full HTTP client for Cypress API testing that operates outside the browser sandbox, avoiding CORS limitations.
  • The implementation resides in the core driver package, specifically within packages/driver/src/cypress/network_utils.ts for request execution and packages/driver/src/cypress/proxy-logging.ts for visibility.
  • Cypress supports all standard HTTP methods, automatic cookie handling, redirect following, and configurable retry logic.
  • You can validate REST and GraphQL APIs independently or combine cy.request() with cy.intercept() to test API integrations within end-to-end workflows.

Frequently Asked Questions

Can Cypress replace dedicated API testing tools like Postman or REST Assured?

While Cypress provides robust API testing capabilities through cy.request(), it is designed primarily as an end-to-end testing framework. It excels when you need to combine API calls with UI interactions or test the full stack, but dedicated API tools may offer more specialized features for standalone API test suites.

Does cy.request() support GraphQL queries?

Yes, cy.request() fully supports GraphQL. You can send POST requests with GraphQL query strings in the body and validate responses using Cypress's assertion library. The command accepts any string or object body content, making it compatible with GraphQL's JSON-based query format.

How does Cypress handle authentication in API requests?

cy.request() accepts an auth property that supports basic authentication (username/password) and bearer tokens via custom headers. Additionally, because Cypress automatically persists cookies across requests, session-based authentication works transparently when making sequential API calls.

Can I stub API responses when using cy.request()?

While cy.request() always executes real HTTP calls, you can combine it with cy.intercept() to stub network traffic that occurs during browser-based tests. For pure API stubbing, use cy.intercept() on the routes your application calls, or use cy.request() to seed data before testing the UI.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →