HTTP

Method

HTTP GET Method: Complete Guide with Examples

Learn how the HTTP GET method works. Understand when to use GET requests, query parameters, caching, and best practices with real-world examples.

6 min read beginner Try in Playground

TL;DR: GET retrieves data from a server without modifying anything. Use it for loading pages, fetching API data, and any read-only operations.

GET is the most fundamental HTTP method. Every time you type a URL in your browser, click a link, or load an image, you’re making a GET request. It’s designed for one purpose: retrieving data without changing anything on the server.

What is GET?

GET requests ask the server to send back a resource. Think of it like asking a librarian for a book—you’re requesting information, not modifying the library’s collection.

GET /api/users/123 HTTP/1.1
Host: api.example.com
Accept: application/json
```text

The server responds with the requested data:

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 123,
  "name": "Alice Johnson",
  "email": "alice@example.com"
}

Key Characteristics

Safe

GET requests never modify data on the server. You can make the same GET request 1,000 times and nothing will be created, updated, or deleted.

✅ GET /users/123      → Returns user data
✅ GET /products       → Returns product list
❌ GET /users/delete   → Never do this!

Idempotent

Making identical GET requests always produces the same result. This property enables:

  • Browser back/forward navigation
  • Automatic retries on network failure
  • Safe prefetching and caching

Cacheable

GET responses can be stored and reused:

HTTP/1.1 200 OK
Cache-Control: max-age=3600
ETag: "abc123"

{"data": "..."}
```text

The browser caches this response for 1 hour, avoiding unnecessary network requests.

### Visible in URL

GET parameters appear in the URL as query strings:

```text
https://shop.example.com/search?q=shoes&color=red&size=10
```javascript

This makes GET requests:

- ✅ Bookmarkable
- ✅ Shareable
- ✅ Visible in browser history
- ❌ Unsuitable for sensitive data

## Query Parameters

Query parameters let you filter, sort, and paginate data:

```http
GET /api/products?category=electronics&sort=price&order=asc&page=2&limit=20 HTTP/1.1
Host: api.example.com

Parameter Syntax

ComponentExamplePurpose
?/search?Starts query string
key=valueq=shoesSingle parameter
&q=shoes&size=10Separates parameters
+ or %20q=red+shoesSpace encoding
%XXq=caf%C3%A9Special character encoding

Common Patterns

Filtering:

GET /products?category=books&price_min=10&price_max=50

Sorting:

GET /products?sort=created_at&order=desc

Pagination:

GET /products?page=3&per_page=25

Searching:

GET /products?q=wireless+headphones

Real-World Examples

Loading a Web Page

GET / HTTP/1.1
Host: howhttpworks.com
Accept: text/html,application/xhtml+xml
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0
```http

### Fetching API Data

```http
GET /api/v1/users?status=active&role=admin HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Accept: application/json

Loading an Image

GET /images/logo.png HTTP/1.1
Host: cdn.example.com
Accept: image/webp,image/png,image/*
If-None-Match: "img-hash-123"
```http

### Conditional Request (Caching)

```http
GET /api/data HTTP/1.1
Host: api.example.com
If-Modified-Since: Sat, 18 Jan 2026 10:00:00 GMT
If-None-Match: "etag-abc123"

If data hasn’t changed, server returns:

HTTP/1.1 304 Not Modified
```javascript

## Common Headers

### Request Headers

| Header              | Purpose                    | Example                         |
| ------------------- | -------------------------- | ------------------------------- |
| `Accept`            | Preferred response format  | `application/json`              |
| `Accept-Language`   | Preferred language         | `en-US,en;q=0.9`                |
| `Accept-Encoding`   | Supported compression      | `gzip, deflate, br`             |
| `Authorization`     | Authentication token       | `Bearer token123`               |
| `If-None-Match`     | Conditional request (ETag) | `"abc123"`                      |
| `If-Modified-Since` | Conditional request (date) | `Sat, 18 Jan 2026 10:00:00 GMT` |
| `Cache-Control`     | Cache directives           | `no-cache`                      |

### Response Headers

| Header           | Purpose              | Example                         |
| ---------------- | -------------------- | ------------------------------- |
| `Content-Type`   | Response format      | `application/json`              |
| `Content-Length` | Body size in bytes   | `1234`                          |
| `Cache-Control`  | Caching rules        | `max-age=3600, public`          |
| `ETag`           | Resource version     | `"abc123"`                      |
| `Last-Modified`  | Last change date     | `Sat, 18 Jan 2026 10:00:00 GMT` |
| `Vary`           | Cache variation keys | `Accept, Accept-Encoding`       |

## Response Status Codes

| Code                                       | Meaning          | When It Happens                         |
| ------------------------------------------ | ---------------- | --------------------------------------- |
| [200 OK](/status-codes/200)                | Success          | Resource found and returned             |
| [304 Not Modified](/status-codes/304)      | Use cache        | Resource unchanged since last request   |
| [400 Bad Request](/status-codes/400)       | Invalid request  | Malformed query parameters              |
| [401 Unauthorized](/status-codes/401)      | Auth required    | Missing or invalid credentials          |
| [403 Forbidden](/status-codes/403)         | Access denied    | Valid auth but insufficient permissions |
| [404 Not Found](/status-codes/404)         | Resource missing | URL doesn't exist                       |
| [429 Too Many Requests](/status-codes/429) | Rate limited     | Too many requests in time window        |

## GET vs POST

| Aspect                  | GET                | POST               |
| ----------------------- | ------------------ | ------------------ |
| **Purpose**             | Retrieve data      | Create/submit data |
| **Data location**       | URL query string   | Request body       |
| **Visible in URL**      | Yes                | No                 |
| **Bookmarkable**        | Yes                | No                 |
| **Cacheable**           | Yes                | No                 |
| **Safe**                | Yes                | No                 |
| **Idempotent**          | Yes                | No                 |
| **Data size limit**     | ~2,000 chars (URL) | No practical limit |
| **Browser back button** | Safe to repeat     | May resubmit data  |

### When to Use Each

**Use GET for:**

- Loading pages and resources
- Search queries
- Filtering and sorting data
- Any read-only operation
- Data you want bookmarkable

**Use POST for:**

- Form submissions
- File uploads
- Creating new resources
- Sensitive data (passwords, payment info)
- Operations that change server state

## Best Practices

### Do's ✅

```javascript
// Fetch data with GET
const response = await fetch('/api/users?status=active')
const users = await response.json()

// Use meaningful URLs
GET /users/123/orders?status=pending

// Include proper headers
GET /api/data HTTP/1.1
Accept: application/json
Authorization: Bearer token

Don’ts ❌

// Never use GET for mutations
GET /api/users/123/delete  // Wrong!
DELETE /api/users/123      // Correct!

// Never put sensitive data in URLs
GET /login?password=secret123  // Exposed in logs!
POST /login with body          // Correct!

// Don't ignore caching
// Always set appropriate Cache-Control headers
```text

### URL Design

```text
✅ Good URLs:
/users/123
/products?category=electronics
/search?q=http+tutorial

❌ Bad URLs:
/api?action=getUser&id=123
/data?type=product&operation=list
```javascript

## JavaScript Examples

### Fetch API

```javascript
// Simple GET
const response = await fetch('https://api.example.com/users')
const users = await response.json()

// With query parameters
const params = new URLSearchParams({
  status: 'active',
  limit: '10'
})
const response = await fetch(`/api/users?${params}`)

// With headers
const response = await fetch('/api/data', {
  method: 'GET',
  headers: {
    Accept: 'application/json',
    Authorization: 'Bearer token123'
  }
})

Error Handling

async function fetchUser(id) {
  const response = await fetch(`/api/users/${id}`)

  if (!response.ok) {
    if (response.status === 404) {
      throw new Error('User not found')
    }
    if (response.status === 401) {
      throw new Error('Please log in')
    }
    throw new Error(`HTTP error: ${response.status}`)
  }

  return response.json()
}

Try It Yourself

Experiment with GET requests in our interactive playground:

  1. Select GET method
  2. Try /posts/1 to fetch a single post
  3. Try /posts?userId=1 to filter by user
  4. Observe the response headers and body
  • POST - Create new resources
  • PUT - Replace entire resources
  • PATCH - Partial updates
  • DELETE - Remove resources
  • HEAD - GET without response body

In Practice

Express.js
// GET /users — list with pagination
app.get('/users', async (req, res) => {
  const { page = 1, limit = 20 } = req.query
  const users = await db.users.findAll({ page: +page, limit: +limit })
  res.json({ users, page: +page, limit: +limit })
})

// GET /users/:id — single resource
app.get('/users/:id', async (req, res) => {
  const user = await db.users.findById(req.params.id)
  if (!user) return res.status(404).json({ error: 'Not found' })
  res.json(user)
})
Next.js App Router
// app/api/users/route.ts
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const page = Number(searchParams.get('page') ?? 1)
  const users = await db.users.findAll({ page })
  return Response.json({ users, page })
}

// app/api/users/[id]/route.ts
export async function GET(
  _req: Request,
  { params }: { params: { id: string } }
) {
  const user = await db.users.findById(params.id)
  if (!user) return new Response(null, { status: 404 })
  return Response.json(user)
}
Django
# views.py
from django.http import JsonResponse
from django.views.decorators.http import require_GET

@require_GET
def user_list(request):
    page = int(request.GET.get('page', 1))
    qs = User.objects.values()[(page - 1) * 20 : page * 20]
    return JsonResponse({'users': list(qs), 'page': page})

@require_GET
def user_detail(request, user_id):
    try:
        user = User.objects.get(pk=user_id)
        return JsonResponse(user.to_dict())
    except User.DoesNotExist:
        return JsonResponse({'error': 'Not found'}, status=404)

Frequently Asked Questions

What is the HTTP GET method?

GET is an HTTP method used to retrieve data from a server. It requests a representation of a specified resource without modifying it. GET is the most common HTTP method, used every time you load a webpage or fetch data from an API.

What is the difference between GET and POST?

GET retrieves data and sends parameters in the URL, while POST sends data in the request body to create or modify resources. GET requests are cacheable and bookmarkable; POST requests are not. GET should never be used for sensitive data like passwords.

Can GET requests have a body?

Technically yes, but it is strongly discouraged. The HTTP specification allows a body in GET requests, but many servers and proxies ignore or reject it. Always use query parameters for GET requests instead of a body.

Are GET requests cached?

Yes, GET responses are cacheable by default. Browsers and CDNs can cache GET responses to improve performance. You can control caching behavior using Cache-Control headers.

What is the maximum URL length for GET requests?

There is no official limit in the HTTP specification, but browsers typically support 2,000-8,000 characters. For safety, keep URLs under 2,000 characters. Use POST for larger data payloads.

Is GET safe and idempotent?

Yes, GET is both safe and idempotent. Safe means it does not modify server state. Idempotent means making the same request multiple times produces the same result. This makes GET requests reliable for retries and caching.

Keep Learning