- Home
- HTTP Methods
- HTTP GET Method: Complete Guide with Examples
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.
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
| Component | Example | Purpose |
|---|---|---|
? | /search? | Starts query string |
key=value | q=shoes | Single parameter |
& | q=shoes&size=10 | Separates parameters |
+ or %20 | q=red+shoes | Space encoding |
%XX | q=caf%C3%A9 | Special 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:
- Select GET method
- Try
/posts/1to fetch a single post - Try
/posts?userId=1to filter by user - Observe the response headers and body
Related Methods
- POST - Create new resources
- PUT - Replace entire resources
- PATCH - Partial updates
- DELETE - Remove resources
- HEAD - GET without response body
Related Concepts
- Query Parameters - URL parameter syntax
- Caching - How GET responses are cached
- Status Codes - Understanding responses
- Content Negotiation - Requesting specific formats
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.