1. Pengenalan Python Requests
Requests adalah library Python yang paling populer untuk mengirim HTTP requests. Dengan slogan "HTTP for Humans", Requests menyederhanakan cara berkomunikasi dengan web services dan REST API.
Dengan Requests, Anda bisa mengambil data dari website, mengirim data ke server, mengunduh file, mengotentikasi pengguna, dan berinteraksi dengan berbagai API — semuanya dengan sintaks yang sangat mudah dipahami.
Mengapa Menggunakan Requests?
| Keunggulan | Penjelasan |
|---|---|
| Sintaks Sederhana | Hanya butuh satu baris untuk mengirim request |
| Otomatis Encoding | JSON, form data, multipart — di-handle otomatis |
| Session Support | Cookies dan headers dipertahankan antar request |
| SSL/TLS | HTTPS dengan verifikasi sertifikat otomatis |
| Authentication | Basic, Digest, OAuth, Bearer Token — built-in |
| Komunitas Besar | Dokumentasi lengkap, digunakan jutaan developer |
HTTP Methods Overview
┌─────────────────────────────────────────────────────────┐ │ HTTP METHODS │ │ │ │ GET ─── Mengambil data dari server │ │ Contoh: Ambil daftar produk │ │ │ │ POST ─── Mengirim data ke server (buat baru) │ │ Contoh: Registrasi user baru │ │ │ │ PUT ─── Memperbarui seluruh data │ │ Contoh: Update profil lengkap │ │ │ │ PATCH ─── Memperbarui sebagian data │ │ Contoh: Update hanya nama │ │ │ │ DELETE ─── Menghapus data │ │ Contoh: Hapus postingan │ │ │ │ HEAD ─── Seperti GET tapi tanpa body │ │ OPTIONS ─── Informasi tentang komunikasi server │ └─────────────────────────────────────────────────────────┘
2. Instalasi dan Setup
Requests bukan library bawaan Python, jadi perlu diinstal terlebih dahulu menggunakan pip.
# Instal requests pip install requests # Verifikasi instalasi python -c "import requests; print(requests.__version__)" # Output: 2.31.0 # Instal dengan fitur tambahan (untuk SOCKS proxy) pip install requests[socks] # Instal dengan fitur security (PyOpenSSL) pip install requests[security]
Quick Start
import requests
# Request pertama — ambil data dari API publik
response = requests.get('https://httpbin.org/get')
# Informasi dasar response
print(response.status_code) # 200
print(response.headers['content-type']) # application/json
print(response.text) # Isi response dalam bentuk string
print(response.json()) # Isi response dalam bentuk dict Python
# Status code kategori
# 2xx = Berhasil (200 OK, 201 Created, 204 No Content)
# 3xx = Redirect (301, 302, 304)
# 4xx = Client Error (400 Bad Request, 401 Unauthorized, 404 Not Found)
# 5xx = Server Error (500 Internal Server Error, 503 Service Unavailable)
# Cek apakah request berhasil
if response.ok: # True untuk status 200-299
print("Request berhasil!")
else:
print(f"Request gagal: {response.status_code}")
3. GET Request
GET adalah HTTP method yang paling umum digunakan untuk mengambil data dari server. Ini adalah method default saat Anda membuka halaman web di browser.
GET dengan Berbagai Parameter
import requests
# ========================================
# GET Sederhana
# ========================================
response = requests.get('https://httpbin.org/get')
print(response.status_code) # 200
# ========================================
# GET dengan Query Parameters
# ========================================
# Cara 1: URL langsung
response = requests.get('https://api.example.com/search?q=python&limit=10')
# Cara 2: Menggunakan params (RECOMMENDED)
params = {
'q': 'python',
'limit': 10,
'page': 1,
'sort': 'relevance'
}
response = requests.get('https://api.example.com/search', params=params)
# URL yang dihasilkan: https://api.example.com/search?q=python&limit=10&page=1&sort=relevance
# Encoding otomatis untuk karakter spesial
params = {'q': 'hello world & python'}
response = requests.get('https://httpbin.org/get', params=params)
print(response.url)
# https://httpbin.org/get?q=hello+world+%26+python
# ========================================
# Mengakses Response Data
# ========================================
response = requests.get('https://httpbin.org/get')
# Response sebagai string
print(response.text)
# Response sebagai bytes
print(response.content)
# Response sebagai JSON (paling umum untuk API)
data = response.json()
print(data['headers']['Host'])
# Response encoding
print(response.encoding) # 'utf-8' (atau None)
response.encoding = 'utf-8' # Set encoding manual jika perlu
# ========================================
# Response Headers
# ========================================
print(response.headers)
print(response.headers['Content-Type'])
print(response.headers.get('X-Custom-Header', 'default'))
# ========================================
# Response Cookies
# ========================================
response = requests.get('https://httpbin.org/cookies/set/token/abc123')
print(response.cookies)
for cookie in response.cookies:
print(f"{cookie.name}: {cookie.value}")
# ========================================
# Timeout — BATAS WAKTU
# ========================================
try:
# Timeout dalam detik (sangat penting untuk production!)
response = requests.get('https://httpbin.org/delay/5', timeout=3)
except requests.exceptions.Timeout:
print("Request timeout! Server terlalu lambat")
# Timeout terpisah untuk connect dan read
response = requests.get('https://httpbin.org/get', timeout=(3.05, 27))
# 3.05 detik untuk connect, 27 detik untuk read
Tanpa timeout, request bisa menggantung selamanya jika server tidak merespons. Selalu set timeout untuk setiap request di production code. Rekomendasi: timeout=(3, 10) untuk connect dan read timeout.
4. POST Request
POST digunakan untuk mengirim data ke server — misalnya saat registrasi, login, mengupload file, atau mengirim form.
Berbagai Tipe POST Data
import requests
# ========================================
# POST dengan Form Data (application/x-www-form-urlencoded)
# ========================================
data = {
'username': 'budi',
'password': 'rahasia123',
'remember': 'true'
}
response = requests.post('https://httpbin.org/post', data=data)
print(response.json()['form']) # Data terkirim sebagai form
# ========================================
# POST dengan JSON (application/json) — PALING UMUM untuk API
# ========================================
json_data = {
'name': 'Budi Santoso',
'email': 'budi@mail.com',
'age': 25,
'hobbies': ['coding', 'gaming', 'reading']
}
response = requests.post('https://httpbin.org/post', json=json_data)
print(response.json()['json']) # Data terkirim sebagai JSON
# Perbedaan data vs json:
# data=data → Content-Type: application/x-www-form-urlencoded
# json=data → Content-Type: application/json (dan auto serialize ke JSON)
# ========================================
# POST dengan Raw Body
# ========================================
import json
# Kirim JSON string secara manual
payload = json.dumps({'key': 'value'})
headers = {'Content-Type': 'application/json'}
response = requests.post(
'https://httpbin.org/post',
data=payload,
headers=headers
)
# ========================================
# POST dengan File Upload (multipart/form-data)
# ========================================
# Upload satu file
files = {'file': open('dokumen.pdf', 'rb')}
response = requests.post('https://httpbin.org/post', files=files)
# Upload dengan metadata
files = {
'file': ('laporan.pdf', open('laporan.pdf', 'rb'), 'application/pdf'),
}
data = {'deskripsi': 'Laporan bulanan', 'kategori': 'bisnis'}
response = requests.post('https://httpbin.org/post', files=files, data=data)
# Upload dari bytes (tanpa buka file)
import io
file_content = b'Ini isi file'
files = {'file': ('data.txt', io.BytesIO(file_content), 'text/plain')}
response = requests.post('https://httpbin.org/post', files=files)
# ========================================
# POST dengan Custom Headers
# ========================================
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiJ9.token',
'X-API-Key': 'my-secret-key',
'User-Agent': 'BeebaneLabs/1.0'
}
response = requests.post(
'https://httpbin.org/post',
json={'data': 'test'},
headers=headers
)
# ========================================
# Membaca Response dari POST
# ========================================
response = requests.post('https://httpbin.org/post', json={'name': 'Budi'})
# Status code
print(response.status_code) # 200 (berhasil) atau 201 (created)
# Response body
data = response.json()
# Headers yang dikirim oleh server
print(response.headers)
# Redirect history (jika ada redirect)
print(response.history) # List of response objects
print(response.url) # URL final setelah redirect
5. PUT, PATCH, DELETE
Selain GET dan POST, REST API juga menggunakan method lain untuk operasi CRUD (Create, Read, Update, Delete).
import requests
BASE_URL = 'https://jsonplaceholder.typicode.com' # API publik untuk testing
# ========================================
# PUT — Update SELURUH resource
# ========================================
data_baru = {
'id': 1,
'title': 'Judul Baru',
'body': 'Isi konten yang sudah diperbarui',
'userId': 1
}
response = requests.put(f'{BASE_URL}/posts/1', json=data_baru)
print(response.status_code) # 200
print(response.json())
# ========================================
# PATCH — Update SEBAGIAN resource
# ========================================
data_sebagian = {
'title': 'Hanya Update Judul'
}
response = requests.patch(f'{BASE_URL}/posts/1', json=data_sebagian)
print(response.status_code) # 200
print(response.json())
# ========================================
# DELETE — Hapus resource
# ========================================
response = requests.delete(f'{BASE_URL}/posts/1')
print(response.status_code) # 200
print(response.json()) # {} (kosong)
# ========================================
# HEAD — Ambil headers saja (tanpa body)
# ========================================
response = requests.head('https://httpbin.org/get')
print(response.headers)
print(response.status_code) # 200
# Berguna untuk cek apakah resource ada
# atau untuk cek Content-Length sebelum download
# ========================================
# OPTIONS — Cek method yang didukung
# ========================================
response = requests.options('https://httpbin.org/post')
print(response.headers.get('Allow')) # GET, HEAD, OPTIONS, POST, PUT
6. Custom Headers dan Cookies
HTTP headers memberikan informasi tambahan pada request dan response. Cookies digunakan untuk menyimpan state (seperti session login).
import requests
# ========================================
# Custom Headers
# ========================================
headers = {
'User-Agent': 'BeebaneLabs-Bot/1.0',
'Accept': 'application/json',
'Accept-Language': 'id-ID,id;q=0.9,en;q=0.8',
'Referer': 'https://beebane.com',
'X-Custom-Header': 'custom-value'
}
response = requests.get('https://httpbin.org/headers', headers=headers)
print(response.json()['headers']['User-Agent'])
# ========================================
# Cookies — Mengirim Cookies
# ========================================
# Cara 1: Melalui parameter cookies
cookies = {
'session_id': 'abc123',
'user_pref': 'dark_mode'
}
response = requests.get('https://httpbin.org/cookies', cookies=cookies)
print(response.json())
# Cara 2: Melalui headers (cookie string)
headers = {'Cookie': 'session_id=abc123; user_pref=dark_mode'}
response = requests.get('https://httpbin.org/cookies', headers=headers)
# ========================================
# Membaca Cookies dari Response
# ========================================
response = requests.get('https://httpbin.org/cookies/set/token/xyz789')
# Akses cookies sebagai dict
print(response.cookies.get('token')) # xyz789
# Iterasi semua cookies
for name, value in response.cookies.items():
print(f"{name} = {value}")
# ========================================
# CookieJar — fitur lanjutan
# ========================================
jar = requests.cookies.RequestsCookieJar()
jar.set('theme', 'dark', domain='example.com', path='/')
jar.set('lang', 'id', domain='example.com', path='/api')
response = requests.get('https://httpbin.org/cookies', cookies=jar)
# ========================================
# Response Headers yang umum
# ========================================
response = requests.get('https://httpbin.org/get')
# Content-Type
print(response.headers['Content-Type'])
# Content-Length
print(response.headers.get('Content-Length'))
# Cache-Control
print(response.headers.get('Cache-Control'))
# Rate Limit headers (umum di API)
# X-RateLimit-Limit: 100
# X-RateLimit-Remaining: 95
# X-RateLimit-Reset: 1625097600
7. Sessions
Session mempertahankan parameter (cookies, headers, auth) di semua request dalam satu sesi. Ini seperti browsing di browser — cookies dan login state dipertahankan antar halaman.
import requests
# ========================================
# Mengapa Menggunakan Session?
# ========================================
# Tanpa session: cookies/header hilang antar request
r1 = requests.get('https://httpbin.org/cookies/set/token/abc')
r2 = requests.get('https://httpbin.org/cookies') # Token HILANG!
# Dengan session: cookies dipertahankan
session = requests.Session()
r1 = session.get('https://httpbin.org/cookies/set/token/abc')
r2 = session.get('https://httpbin.org/cookies')
print(r2.json()) # {'cookies': {'token': 'abc'}} — Token TERSIMPAN!
# ========================================
# Session dengan Default Headers
# ========================================
session = requests.Session()
# Set default headers untuk semua request dalam session
session.headers.update({
'User-Agent': 'BeebaneLabs/1.0',
'Accept': 'application/json',
'Authorization': 'Bearer my-jwt-token'
})
# Semua request otomatis pakai headers di atas
r1 = session.get('https://httpbin.org/get')
r2 = session.post('https://httpbin.org/post', json={'test': 1})
# ========================================
# Session dengan Default Auth
# ========================================
from requests.auth import HTTPBasicAuth
session = requests.Session()
session.auth = HTTPBasicAuth('username', 'password')
# Semua request otomatis pakai basic auth
r1 = session.get('https://httpbin.org/basic-auth/username/password')
print(r1.status_code) # 200
# ========================================
# Contoh Praktis: Login dan Akses Protected Page
# ========================================
session = requests.Session()
# Step 1: Login
login_data = {
'username': 'budi',
'password': 'rahasia'
}
login_response = session.post('https://httpbin.org/post', data=login_data)
# Step 2: Akses halaman yang butuh login
# Cookies dari login otomatis terkirim!
profile = session.get('https://httpbin.org/get')
# Step 3: Logout (opsional)
session.close() # Tutup session
# ========================================
# Menggunakan Session sebagai Context Manager
# ========================================
with requests.Session() as session:
session.headers['Authorization'] = 'Bearer token123'
response = session.get('https://httpbin.org/get')
# Session otomatis ditutup di akhir blok
# ========================================
# Connection Pooling dengan Session
# ========================================
# Session melakukan connection pooling — membuat koneksi
# ke host yang sama lebih efisien. Gunakan session untuk
# multiple request ke server yang sama.
session = requests.Session()
# Lebih cepat dari requests.get() terpisah karena:
# 1. TCP connection di-reuse
# 2. TLS handshake hanya dilakukan sekali
for i in range(10):
r = session.get(f'https://httpbin.org/get?page={i}')
print(f"Page {i}: {r.status_code}")
session.close()
8. Authentication
Requests mendukung berbagai metode autentikasi secara built-in. Berikut metode yang paling umum digunakan.
import requests
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
# ========================================
# 1. Basic Authentication
# Username dan password dikirim base64-encoded
# ========================================
response = requests.get(
'https://httpbin.org/basic-auth/budi/rahasia',
auth=HTTPBasicAuth('budi', 'rahasia')
)
print(response.status_code) # 200
print(response.json()) # {'authenticated': True, 'user': 'budi'}
# Shortcut — sama persis
response = requests.get(
'https://httpbin.org/basic-auth/budi/rahasia',
auth=('budi', 'rahasia')
)
# ========================================
# 2. Digest Authentication
# Lebih aman dari Basic Auth
# ========================================
response = requests.get(
'https://httpbin.org/digest-auth/auth/budi/rahasia',
auth=HTTPDigestAuth('budi', 'rahasia')
)
print(response.status_code) # 200
# ========================================
# 3. Bearer Token (JWT/OAuth2)
# Paling umum di REST API modern
# ========================================
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U'
# Cara 1: Manual header
headers = {'Authorization': f'Bearer {token}'}
response = requests.get('https://httpbin.org/bearer', headers=headers)
# Cara 2: Custom Auth class
class BearerAuth(requests.auth.AuthBase):
def __init__(self, token):
self.token = token
def __call__(self, r):
r.headers['Authorization'] = f'Bearer {self.token}'
return r
response = requests.get('https://httpbin.org/get', auth=BearerAuth(token))
# ========================================
# 4. API Key Authentication
# Biasanya dikirim di header atau query parameter
# ========================================
# Via Header (lebih aman)
headers = {'X-API-Key': 'my-secret-api-key'}
response = requests.get('https://httpbin.org/get', headers=headers)
# Via Query Parameter
params = {'api_key': 'my-secret-api-key'}
response = requests.get('https://httpbin.org/get', params=params)
# ========================================
# 5. OAuth2 Flow (sederhana)
# ========================================
# Untuk OAuth2 kompleks, gunakan library requests-oauthlib
# pip install requests-oauthlib
# OAuth2 Client Credentials (sederhana)
def get_oauth_token(client_id, client_secret, token_url):
response = requests.post(token_url, data={
'grant_type': 'client_credentials',
'client_id': client_id,
'client_secret': client_secret
})
return response.json()['access_token']
# Gunakan token
# token = get_oauth_token('client_id', 'secret', 'https://auth.example.com/token')
# headers = {'Authorization': f'Bearer {token}'}
# response = requests.get('https://api.example.com/data', headers=headers)
9. Error Handling
Error handling adalah bagian krusial saat bekerja dengan HTTP requests. Jaringan bisa down, server bisa error, dan timeout bisa terjadi kapan saja.
import requests
from requests.exceptions import (
ConnectionError,
Timeout,
HTTPError,
RequestException,
TooManyRedirects,
JSONDecodeError
)
# ========================================
# 1. raise_for_status() — Cara Paling Umum
# ========================================
try:
response = requests.get('https://httpbin.org/status/404', timeout=5)
response.raise_for_status() # Raise HTTPError untuk 4xx/5xx
data = response.json()
except HTTPError as e:
print(f"HTTP Error: {e}")
print(f"Status Code: {e.response.status_code}")
# HTTP Error: 404 Client Error: Not Found
# ========================================
# 2. Mengecek Status Secara Manual
# ========================================
response = requests.get('https://httpbin.org/status/200')
if response.status_code == 200:
data = response.json()
elif response.status_code == 404:
print("Resource tidak ditemukan")
elif response.status_code == 401:
print("Unauthorized — perlu login")
elif response.status_code == 429:
print("Rate limit exceeded — tunggu sebentar")
elif response.status_code >= 500:
print("Server error — coba lagi nanti")
# Atau dengan ok property
if response.ok: # True untuk 200-299
print("Berhasil!")
# ========================================
# 3. Comprehensive Error Handling
# ========================================
def fetch_api(url, params=None, max_retries=3):
"""Fungsi helper untuk fetch API dengan error handling lengkap"""
for attempt in range(max_retries):
try:
response = requests.get(
url,
params=params,
timeout=(3.05, 27), # (connect timeout, read timeout)
headers={'Accept': 'application/json'}
)
response.raise_for_status()
return response.json()
except ConnectionError:
print(f"Koneksi gagal (percobaan {attempt + 1}/{max_retries})")
except Timeout:
print(f"Request timeout (percobaan {attempt + 1}/{max_retries})")
except HTTPError as e:
status = e.response.status_code
if status == 429: # Rate limit
import time
wait = int(e.response.headers.get('Retry-After', 60))
print(f"Rate limit! Tunggu {wait} detik...")
time.sleep(wait)
continue
elif status >= 500: # Server error, bisa retry
print(f"Server error {status}, retry...")
continue
else:
print(f"HTTP Error {status}: {e}")
return None
except JSONDecodeError:
print("Response bukan JSON valid")
return None
except RequestException as e:
print(f"Request error: {e}")
return None
print(f"Gagal setelah {max_retries} percobaan")
return None
# Gunakan fungsi helper
data = fetch_api('https://httpbin.org/get')
if data:
print("Data berhasil diambil:", data)
# ========================================
# 4. Timeout yang Tepat
# ========================================
# Timeout tuple: (connect_timeout, read_timeout)
# connect_timeout: waktu untuk membuat koneksi TCP
# read_timeout: waktu tunggu server mengirim data
try:
# API cepat — timeout pendek
r = requests.get('https://httpbin.org/get', timeout=(2, 5))
# API lambat (heavy processing) — timeout panjang
r = requests.get('https://httpbin.org/delay/10', timeout=(3, 30))
# Download file besar — timeout sangat panjang
# Atau gunakan stream=True
r = requests.get('https://example.com/large-file.zip',
timeout=(3, 300), stream=True)
except Timeout:
print("Timeout!")
Ringkasan Exception Requests
| Exception | Penyebab |
|---|---|
ConnectionError | Gagal membuat koneksi (DNS, network down) |
Timeout | Request melebihi batas waktu |
HTTPError | Status code 4xx/5xx (via raise_for_status) |
TooManyRedirects | Redirect melebihi batas |
JSONDecodeError | Response bukan JSON valid |
RequestException | Base class untuk semua exception |
10. Contoh Praktis
Download File dan Progress Bar
import requests
def download_file(url, filename):
"""Download file dengan progress tracking"""
response = requests.get(url, stream=True, timeout=30)
response.raise_for_status()
total_size = int(response.headers.get('content-length', 0))
downloaded = 0
with open(filename, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
downloaded += len(chunk)
if total_size:
percent = (downloaded / total_size) * 100
print(f"\rDownloading: {percent:.1f}%", end='')
print(f"\nFile tersimpan: {filename}")
# Contoh penggunaan
# download_file('https://example.com/file.zip', 'file.zip')
Contoh: Interaksi dengan REST API Lengkap
import requests
class APIClient:
"""Contoh REST API Client menggunakan Requests"""
def __init__(self, base_url, api_key=None):
self.base_url = base_url.rstrip('/')
self.session = requests.Session()
self.session.headers.update({
'Accept': 'application/json',
'Content-Type': 'application/json'
})
if api_key:
self.session.headers['Authorization'] = f'Bearer {api_key}'
def _request(self, method, endpoint, **kwargs):
url = f"{self.base_url}/{endpoint.lstrip('/')}"
kwargs.setdefault('timeout', (3, 10))
response = self.session.request(method, url, **kwargs)
response.raise_for_status()
return response.json()
def get(self, endpoint, params=None):
return self._request('GET', endpoint, params=params)
def post(self, endpoint, data=None):
return self._request('POST', endpoint, json=data)
def put(self, endpoint, data=None):
return self._request('PUT', endpoint, json=data)
def patch(self, endpoint, data=None):
return self._request('PATCH', endpoint, json=data)
def delete(self, endpoint):
return self._request('DELETE', endpoint)
def close(self):
self.session.close()
def __enter__(self):
return self
def __exit__(self, *args):
self.close()
# Menggunakan API Client
with APIClient('https://jsonplaceholder.typicode.com') as api:
# Ambil semua posts
posts = api.get('/posts')
print(f"Total posts: {len(posts)}")
# Ambil post tertentu
post = api.get('/posts/1')
print(f"Judul: {post['title']}")
# Buat post baru
new_post = api.post('/posts', {
'title': 'Postingan Baru',
'body': 'Isi postingan dari Python',
'userId': 1
})
print(f"Post dibuat dengan ID: {new_post['id']}")
# Update post
updated = api.put('/posts/1', {
'title': 'Judul Diperbarui',
'body': 'Isi baru',
'userId': 1
})
# Delete post
api.delete('/posts/1')
print("Post berhasil dihapus")
1. Selalu gunakan Session untuk multiple request ke server yang sama (connection pooling). 2. Selalu set timeout. 3. Gunakan raise_for_status() atau cek status secara manual. 4. Simpan API key di environment variable, jangan hardcode. 5. Gunakan stream=True untuk download file besar.
11. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Python Requests: