Learn from practical code examples
Make HTTP requests using the Fetch API with proper error handling and async/await syntax.
async function fetchUser(userId) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const user = await response.json();
return user;
} catch (error) {
console.error('Failed to fetch user:', error);
throw error;
}
}
// Usage
fetchUser(1)
.then(user => console.log(user))
.catch(error => console.error(error));This example demonstrates how to use the Fetch API with async/await syntax. It includes proper error handling for both network errors and HTTP error responses. The response.ok property checks if the status is in the 200-299 range.
Implement a debounce function to limit how often a function can be called.
function debounce(func, wait) {
let timeoutId;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeoutId);
func(...args);
};
clearTimeout(timeoutId);
timeoutId = setTimeout(later, wait);
};
}
// Usage: Debounce search input
const searchInput = document.querySelector('#search');
const debouncedSearch = debounce((query) => {
console.log('Searching for:', query);
// Make API call here
}, 300);
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});Debouncing ensures that a function is only called after a certain amount of time has passed since the last call. This is useful for search inputs, window resize handlers, and other events that fire rapidly.
Store data in localStorage with automatic expiration.
const storage = {
set(key, value, expiryInMinutes) {
const item = {
value: value,
expiry: Date.now() + expiryInMinutes * 60 * 1000
};
localStorage.setItem(key, JSON.stringify(item));
},
get(key) {
const itemStr = localStorage.getItem(key);
if (!itemStr) return null;
const item = JSON.parse(itemStr);
if (Date.now() > item.expiry) {
localStorage.removeItem(key);
return null;
}
return item.value;
},
remove(key) {
localStorage.removeItem(key);
}
};
// Usage
storage.set('user', { name: 'John' }, 60); // Expires in 60 minutes
const user = storage.get('user');
console.log(user); // { name: 'John' } or null if expiredThis utility wraps localStorage to add automatic expiration. Data is stored with a timestamp, and when retrieved, the function checks if the data has expired before returning it.
Safely read files using Python's context manager pattern.
# Reading a text file
def read_file(filepath):
"""Read and return the contents of a file."""
try:
with open(filepath, 'r', encoding='utf-8') as file:
content = file.read()
return content
except FileNotFoundError:
print(f"File not found: {filepath}")
return None
except PermissionError:
print(f"Permission denied: {filepath}")
return None
# Reading line by line (memory efficient)
def read_lines(filepath):
"""Read a file line by line."""
with open(filepath, 'r', encoding='utf-8') as file:
for line in file:
yield line.strip()
# Usage
content = read_file('example.txt')
if content:
print(content)
# Process large files
for line in read_lines('large_file.txt'):
print(line)Using 'with' statement (context manager) ensures the file is properly closed even if an error occurs. The generator version is memory-efficient for large files as it reads one line at a time.
Make HTTP requests using the popular requests library.
import requests
def fetch_data(url, params=None, headers=None):
"""Make a GET request with error handling."""
try:
response = requests.get(
url,
params=params,
headers=headers,
timeout=10
)
response.raise_for_status()
return response.json()
except requests.exceptions.Timeout:
print("Request timed out")
except requests.exceptions.HTTPError as e:
print(f"HTTP error: {e}")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
def post_data(url, data, headers=None):
"""Make a POST request."""
try:
response = requests.post(
url,
json=data,
headers=headers,
timeout=10
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
# Usage
users = fetch_data('https://api.example.com/users')
new_user = post_data(
'https://api.example.com/users',
{'name': 'John', 'email': 'john@example.com'}
)This example shows how to make GET and POST requests with the requests library. It includes timeout settings and comprehensive error handling for different types of request failures.
Implement type guards to narrow types in TypeScript.
// Type definitions
interface Dog {
type: 'dog';
bark(): void;
}
interface Cat {
type: 'cat';
meow(): void;
}
type Pet = Dog | Cat;
// Type guard using type predicate
function isDog(pet: Pet): pet is Dog {
return pet.type === 'dog';
}
function isCat(pet: Pet): pet is Cat {
return pet.type === 'cat';
}
// Using the type guards
function handlePet(pet: Pet) {
if (isDog(pet)) {
pet.bark(); // TypeScript knows pet is Dog
} else {
pet.meow(); // TypeScript knows pet is Cat
}
}
// Type guard for checking if value exists
function isNotNull<T>(value: T | null | undefined): value is T {
return value !== null && value !== undefined;
}
// Usage
const values = [1, null, 2, undefined, 3];
const filtered = values.filter(isNotNull);
// filtered is number[] instead of (number | null | undefined)[]Type guards are functions that narrow the type of a variable within a conditional block. The 'is' keyword in the return type creates a type predicate that TypeScript uses to narrow types.
Common TypeScript utility types for type transformations.
interface User {
id: number;
name: string;
email: string;
age: number;
}
// Partial<T> - All properties optional
type PartialUser = Partial<User>;
const update: PartialUser = { name: 'New Name' };
// Required<T> - All properties required
type RequiredUser = Required<PartialUser>;
// Pick<T, K> - Select specific properties
type UserPreview = Pick<User, 'id' | 'name'>;
const preview: UserPreview = { id: 1, name: 'John' };
// Omit<T, K> - Exclude specific properties
type UserWithoutId = Omit<User, 'id'>;
// Record<K, T> - Create object type with keys K and values T
type UserRoles = Record<string, 'admin' | 'user' | 'guest'>;
const roles: UserRoles = {
john: 'admin',
jane: 'user'
};
// Readonly<T> - All properties readonly
type ReadonlyUser = Readonly<User>;
const immutableUser: ReadonlyUser = {
id: 1,
name: 'John',
email: 'john@example.com',
age: 30
};
// immutableUser.name = 'Jane'; // Error!TypeScript provides built-in utility types for common type transformations. These help create new types based on existing ones without duplicating type definitions.
Build a simple HTTP server in Go with multiple routes and JSON responses.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
users := []User{{ID: 1, Name: "Alice"}, {ID: 2, Name: "Bob"}}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/users", usersHandler)
fmt.Println("Listening on :8080")
log.Fatal(http.ListenAndServe(":8080", mux))
}Go stdlib includes a production-ready HTTP server. NewServeMux routes requests; json.NewEncoder streams JSON directly to the ResponseWriter without creating an intermediate buffer.
Concurrent programming with goroutines and channels — Go's approach to parallelism.
package main
import (
"fmt"
"sync"
)
func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for job := range jobs {
results <- job * job
}
}
func main() {
jobs := make(chan int, 10)
results := make(chan int, 10)
var wg sync.WaitGroup
for w := 1; w <= 3; w++ {
wg.Add(1)
go worker(w, jobs, results, &wg)
}
for j := 1; j <= 9; j++ { jobs <- j }
close(jobs)
go func() { wg.Wait(); close(results) }()
sum := 0
for r := range results { sum += r }
fmt.Println("Sum of squares:", sum)
}Goroutines are lightweight threads managed by the Go runtime. Channels are typed communication pipes. This worker pool distributes jobs across 3 goroutines; WaitGroup ensures all complete before closing the results channel.
Rust's ownership system — memory safety without garbage collection.
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 moved — no longer valid
println!("{}", s2);
let s3 = String::from("world");
let s4 = s3.clone(); // deep copy — both valid
println!("{} {}", s3, s4);
let len = calc_len(&s4); // borrow, s4 still owned
println!("len={}", len);
let mut s5 = String::from("hi");
append(&mut s5);
println!("{}", s5); // "hi, world"
}
fn calc_len(s: &String) -> usize { s.len() }
fn append(s: &mut String) { s.push_str(", world"); }Each Rust value has exactly one owner. Assignment moves ownership; clone() makes a deep copy. References borrow without owning. Rule: one &mut borrow OR many & borrows — never both simultaneously.
Idiomatic Rust errors using Result, the ? operator, and From trait conversions.
use std::num::ParseIntError;
use std::fmt;
#[derive(Debug)]
enum AppError { Parse(ParseIntError), Negative }
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AppError::Parse(e) => write!(f, "parse error: {}", e),
AppError::Negative => write!(f, "must be positive"),
}
}
}
impl From<ParseIntError> for AppError {
fn from(e: ParseIntError) -> Self { AppError::Parse(e) }
}
fn parse_pos(s: &str) -> Result<u32, AppError> {
let n: i64 = s.parse()?; // ? converts via From
if n < 0 { return Err(AppError::Negative); }
Ok(n as u32)
}
fn main() {
println!("{:?}", parse_pos("42")); // Ok(42)
println!("{:?}", parse_pos("-5")); // Err(Negative)
println!("{:?}", parse_pos("abc")); // Err(Parse(...))
}Result<T,E> makes errors explicit in the type system — no exceptions. The ? operator propagates errors early, converting types via From. Custom error enums ensure exhaustive handling; the compiler rejects unhandled variants.
Java 8+ Streams for functional-style data processing: filter, map, groupBy, reduce.
import java.util.*;
import java.util.stream.*;
public class StreamExample {
record Person(String name, int age, String city) {}
public static void main(String[] args) {
var people = List.of(
new Person("Alice", 30, "NYC"),
new Person("Bob", 25, "LA"),
new Person("Carol", 35, "NYC")
);
var nycNames = people.stream()
.filter(p -> p.city().equals("NYC"))
.map(Person::name).sorted().toList();
System.out.println(nycNames); // [Alice, Carol]
people.stream()
.collect(Collectors.groupingBy(Person::city))
.forEach((city, ps) ->
System.out.println(city + ": " + ps.size()));
people.stream().mapToInt(Person::age)
.average()
.ifPresent(avg -> System.out.printf("Avg: %.1f%n", avg));
}
}Streams are lazy pipelines: intermediate ops (filter, map) don't run until a terminal op (toList, average) triggers evaluation. Records are concise immutable data classes with auto-generated accessors, equals, and toString.
Reusable data-access abstraction using Java generics and interfaces.
import java.util.*;
interface Repository<T, ID> {
Optional<T> findById(ID id);
List<T> findAll();
T save(T entity);
}
record User(int id, String name) {}
class MemUserRepo implements Repository<User, Integer> {
private final Map<Integer, User> db = new HashMap<>();
public Optional<User> findById(Integer id) {
return Optional.ofNullable(db.get(id));
}
public List<User> findAll() { return List.copyOf(db.values()); }
public User save(User u) { db.put(u.id(), u); return u; }
}
public class Main {
public static void main(String[] args) {
Repository<User, Integer> repo = new MemUserRepo();
repo.save(new User(1, "Alice"));
repo.save(new User(2, "Bob"));
repo.findById(1).ifPresent(u -> System.out.println(u.name()));
System.out.println(repo.findAll().size() + " users");
}
}Generic interfaces let you swap implementations without changing call sites. Optional<T> forces handling of missing values. The compiler ensures all interface methods are implemented.
Language Integrated Query for expressive, SQL-like data manipulation in C#.
using System; using System.Collections.Generic; using System.Linq;
record Product(int Id, string Name, string Category, decimal Price);
var products = new List<Product> {
new(1, "Laptop", "Electronics", 999.99m),
new(2, "Phone", "Electronics", 699.99m),
new(3, "Desk", "Furniture", 299.99m),
new(4, "Chair", "Furniture", 199.99m),
};
var expensive = products
.Where(p => p.Price > 300)
.OrderByDescending(p => p.Price)
.Select(p => p.Name + ": $" + p.Price);
Console.WriteLine(string.Join(", ", expensive));
products.GroupBy(p => p.Category)
.Select(g => new { Category = g.Key, Total = g.Sum(p => p.Price) })
.ToList()
.ForEach(s => Console.WriteLine(s.Category + ": $" + s.Total.ToString("F2")));
Console.WriteLine("Average: $" + products.Average(p => p.Price).ToString("F2"));LINQ's fluent API makes queries readable and composable. Where/Select/GroupBy are lazy — they execute only when enumerated. Records provide immutable value objects with structural equality and minimal boilerplate.
Parallel async requests with CancellationToken and proper HttpClient usage in C#.
using System; using System.Linq;
using System.Net.Http; using System.Net.Http.Json;
using System.Threading; using System.Threading.Tasks;
record Post(int Id, string Title);
class Program {
static readonly HttpClient http = new(); // share — never new per-request
static async Task<Post> FetchAsync(int id, CancellationToken ct) =>
await http.GetFromJsonAsync<Post>(
"https://jsonplaceholder.typicode.com/posts/" + id, ct)
?? throw new Exception("not found");
static async Task Main() {
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
try {
// parallel requests — like Promise.all
var posts = await Task.WhenAll(
new[] {1, 2, 3}.Select(id => FetchAsync(id, cts.Token)));
foreach (var p in posts)
Console.WriteLine("#" + p.Id + ": " + p.Title);
}
catch (OperationCanceledException) {
Console.Error.WriteLine("Timed out");
}
}
}Task.WhenAll runs tasks in parallel (= Promise.all). CancellationTokenSource adds a hard timeout. HttpClient must be shared (static) to avoid socket exhaustion. GetFromJsonAsync<T> deserializes the response body to a typed record in one call.