Understanding RESTful Web Services
What is a RESTful Web Service?
A RESTful web service (also called a REST API) is a way for computer programs to communicate with each other over the internet. Think of it like a restaurant:
- You (the customer) = Your application
- The menu = The API documentation (tells you what's available)
- Your order = An API request
- The waiter = The API (delivers your request to the kitchen)
- The kitchen = The server/database
- Your food = The API response (the data you requested)
Just like you tell the waiter what you want from the menu, your application tells the API what data it wants to create, read, update, or delete.
What Does REST Stand For?
REST stands for REpresentational State Transfer. Don't worry too much about the formal definition - what matters is understanding how to use it.
Key Characteristics of REST
- Uses HTTP: REST uses the same protocol your web browser uses to load websites
- Stateless: Each request is independent - the server doesn't remember previous requests
- Resource-Based: Everything is treated as a "resource" (like a customer, product, or order)
- Standard Methods: Uses standard HTTP verbs (GET, POST, PUT, DELETE) to perform actions
- Returns Data: Usually returns data in JSON format (easy for programs to read)
Understanding Resources: Collections and Objects
In REST, everything is a resource. Resources come in two main types: collections and objects (also called individual resources or items).
Collections
A collection is a group of similar items. Think of it like a filing cabinet drawer that holds multiple folders.
/customers- A collection of all customers/products- A collection of all products/orders- A collection of all orders/merchants/12345678901/payors- A collection of all payors for a specific merchant
Collection URLs typically use plural nouns (customers, products, orders).
Objects (Individual Resources)
An object is a single, specific item within a collection. Think of it like one specific folder from that filing cabinet.
/customers/12345- A specific customer with ID 12345/products/ABC-789- A specific product with ID ABC-789/orders/ORD-2024-001- A specific order/merchants/12345678901/payors/5513027774438108364- A specific payor
Object URLs include an identifier (ID) that specifies which exact item you want.
Nested Resources
Resources can be nested to show relationships. For example, payment methods belong to a payor:
This URL structure tells us: "Get the payment method with ID {paymentMethodId} that belongs to payor {payorId} under merchant {merchantId}."
HTTP Verbs (Methods)
HTTP verbs (also called methods) tell the API what action you want to perform. Think of them as action words - verbs that describe what you want to do with a resource.
| HTTP Verb | Purpose | What It Does | Safe? | Idempotent? |
|---|---|---|---|---|
| GET | Read/Retrieve | Gets data without changing anything | Yes | Yes |
| POST | Create | Creates a new resource | No | No |
| PUT | Update/Replace | Updates an existing resource (replaces it) | No | Yes |
| PATCH | Partial Update | Updates part of an existing resource | No | No |
| DELETE | Delete | Removes a resource | No | Yes |
- Safe: A method is "safe" if it doesn't modify any data on the server. You can call it repeatedly without side effects.
- Idempotent: A method is "idempotent" if calling it multiple times has the same effect as calling it once. For example, deleting the same resource twice results in the same state (resource is deleted).
GET - Retrieve Data
Use GET to retrieve data without making any changes.
Effect: Returns a list of all customers (does not modify anything)
Effect: Returns details about customer with ID 12345
POST - Create New Resource
Use POST to create a new resource in a collection.
Effect: Creates a new customer with the data you provide in the request body
Returns: Usually returns the newly created resource with its assigned ID
PUT - Update/Replace Resource
Use PUT to update an existing resource (typically replaces the entire resource).
Effect: Updates customer 12345 with the new data you provide
Returns: Usually returns the updated resource
DELETE - Remove Resource
Use DELETE to remove a resource.
Effect: Deletes customer with ID 12345
Returns: Usually returns a success message or the deleted resource
HTTP Verbs and CRUD Operations
CRUD stands for Create, Read, Update, Delete - the four basic operations you can perform on data. HTTP verbs map directly to CRUD operations:
| CRUD Operation | HTTP Verb | Applied to Collection | Applied to Object |
|---|---|---|---|
| Create | POST | POST /customersCreates a new customer |
Not typically used |
| Read | GET | GET /customersGet all customers |
GET /customers/12345Get specific customer |
| Update | PUT or PATCH | Not typically used | PUT /customers/12345Update customer 12345 |
| Delete | DELETE | DELETE /customersDelete all customers (rare) |
DELETE /customers/12345Delete customer 12345 |
Common REST API Patterns
Pattern 1: List All Items in a Collection
Purpose: Retrieve a list of all customers
Returns: An array of customer objects
Pattern 2: Get a Specific Item
Purpose: Retrieve details about customer with ID 12345
Returns: A single customer object
Pattern 3: Create a New Item
Purpose: Create a new customer
Send: Customer data in the request body (JSON)
Returns: The newly created customer with its assigned ID
Pattern 4: Update an Existing Item
Purpose: Update customer 12345
Send: Updated customer data in the request body
Returns: The updated customer object
Pattern 5: Delete an Item
Purpose: Delete customer 12345
Returns: Success message or the deleted customer object
Pattern 6: Get Nested Resources
Purpose: Get all orders for customer 12345
Returns: An array of order objects belonging to that customer
Making REST API Calls - Code Examples
Example 1: GET Request - Retrieve a Customer
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
public class RestApiClient
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl = "https://api.example.com";
private readonly string _bearerToken;
public RestApiClient(string bearerToken)
{
_bearerToken = bearerToken;
_httpClient = new HttpClient();
_httpClient.BaseAddress = new Uri(_baseUrl);
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", _bearerToken);
_httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
// GET - Retrieve a single customer
public async Task<string> GetCustomerAsync(string customerId)
{
string endpoint = $"/customers/{customerId}";
HttpResponseMessage response = await _httpClient.GetAsync(endpoint);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
// GET - Retrieve all customers
public async Task<string> GetAllCustomersAsync()
{
string endpoint = "/customers";
HttpResponseMessage response = await _httpClient.GetAsync(endpoint);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
// Usage:
var client = new RestApiClient("your-bearer-token");
string customer = await client.GetCustomerAsync("12345");
Console.WriteLine(customer);
Imports System
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Threading.Tasks
Public Class RestApiClient
Private ReadOnly _httpClient As HttpClient
Private ReadOnly _baseUrl As String = "https://api.example.com"
Private ReadOnly _bearerToken As String
Public Sub New(bearerToken As String)
_bearerToken = bearerToken
_httpClient = New HttpClient()
_httpClient.BaseAddress = New Uri(_baseUrl)
_httpClient.DefaultRequestHeaders.Authorization =
New AuthenticationHeaderValue("Bearer", _bearerToken)
_httpClient.DefaultRequestHeaders.Accept.Add(
New MediaTypeWithQualityHeaderValue("application/json"))
End Sub
' GET - Retrieve a single customer
Public Async Function GetCustomerAsync(customerId As String) As Task(Of String)
Dim endpoint As String = $"/customers/{customerId}"
Dim response As HttpResponseMessage = Await _httpClient.GetAsync(endpoint)
response.EnsureSuccessStatusCode()
Return Await response.Content.ReadAsStringAsync()
End Function
' GET - Retrieve all customers
Public Async Function GetAllCustomersAsync() As Task(Of String)
Dim endpoint As String = "/customers"
Dim response As HttpResponseMessage = Await _httpClient.GetAsync(endpoint)
response.EnsureSuccessStatusCode()
Return Await response.Content.ReadAsStringAsync()
End Function
End Class
' Usage:
Dim client As New RestApiClient("your-bearer-token")
Dim customer As String = Await client.GetCustomerAsync("12345")
Console.WriteLine(customer)
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class RestApiClient {
private final String baseUrl;
private final String bearerToken;
private final HttpClient httpClient;
public RestApiClient(String baseUrl, String bearerToken) {
this.baseUrl = baseUrl;
this.bearerToken = bearerToken;
this.httpClient = HttpClient.newHttpClient();
}
// GET - Retrieve a single customer
public String getCustomer(String customerId) throws IOException, InterruptedException {
String endpoint = baseUrl + "/customers/" + customerId;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("Authorization", "Bearer " + bearerToken)
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> response = httpClient.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
throw new IOException("HTTP Error: " + response.statusCode());
}
return response.body();
}
// GET - Retrieve all customers
public String getAllCustomers() throws IOException, InterruptedException {
String endpoint = baseUrl + "/customers";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("Authorization", "Bearer " + bearerToken)
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> response = httpClient.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
throw new IOException("HTTP Error: " + response.statusCode());
}
return response.body();
}
}
// Usage:
RestApiClient client = new RestApiClient("https://api.example.com", "your-bearer-token");
String customer = client.getCustomer("12345");
System.out.println(customer);
require 'net/http'
require 'uri'
require 'json'
class RestApiClient
def initialize(base_url, bearer_token)
@base_url = base_url
@bearer_token = bearer_token
end
# GET - Retrieve a single customer
def get_customer(customer_id)
endpoint = "#{@base_url}/customers/#{customer_id}"
uri = URI.parse(endpoint)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.path)
request['Authorization'] = "Bearer #{@bearer_token}"
request['Accept'] = 'application/json'
response = http.request(request)
if response.code.to_i != 200
raise "HTTP Error: #{response.code} - #{response.body}"
end
response.body
end
# GET - Retrieve all customers
def get_all_customers
endpoint = "#{@base_url}/customers"
uri = URI.parse(endpoint)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.path)
request['Authorization'] = "Bearer #{@bearer_token}"
request['Accept'] = 'application/json'
response = http.request(request)
if response.code.to_i != 200
raise "HTTP Error: #{response.code} - #{response.body}"
end
response.body
end
end
# Usage:
client = RestApiClient.new('https://api.example.com', 'your-bearer-token')
customer = client.get_customer('12345')
puts customer
Note: The remaining code examples (POST, PUT, DELETE) follow the same patterns shown above with the appropriate HTTP verb changes. See the full page for complete examples.
HTTP Status Codes
When you make a REST API request, the server responds with a status code that tells you whether the request was successful or if something went wrong.
| Status Code | Category | Meaning | Examples |
|---|---|---|---|
| 2xx | Success | The request was successful |
200 OK - Request succeeded 201 Created - New resource created 204 No Content - Success, but no content to return |
| 3xx | Redirection | Further action is needed |
301 Moved Permanently - Resource moved 304 Not Modified - Cached version is still valid |
| 4xx | Client Error | There's a problem with your request |
400 Bad Request - Invalid data sent 401 Unauthorized - Authentication required 403 Forbidden - You don't have permission 404 Not Found - Resource doesn't exist 409 Conflict - Request conflicts with current state |
| 5xx | Server Error | The server encountered an error |
500 Internal Server Error - Server error 503 Service Unavailable - Server temporarily unavailable |
Request and Response Format (JSON)
Most REST APIs use JSON (JavaScript Object Notation) to send and receive data. JSON is a simple text format that's easy for both humans and computers to read.
Example JSON Request Body (POST /customers)
{
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phone": "555-1234",
"address": {
"street": "123 Main St",
"city": "Springfield",
"state": "IL",
"zipCode": "62701"
}
}
Example JSON Response Body
{
"id": "12345",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phone": "555-1234",
"address": {
"street": "123 Main St",
"city": "Springfield",
"state": "IL",
"zipCode": "62701"
},
"createdDate": "2026-04-02T10:30:00Z",
"lastModifiedDate": "2026-04-02T10:30:00Z"
}
Authentication
Most REST APIs require authentication to verify who you are. The most common method is
using a Bearer Token in the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Think of the bearer token like a temporary access card - you get it after logging in, and you show it with every request to prove you're authorized.
Best Practices for Working with REST APIs
1. Use HTTPS
Always use HTTPS (not HTTP) to ensure data is encrypted during transmission. This is especially important when sending sensitive information like passwords or payment details.
2. Handle Errors Gracefully
Always check the HTTP status code and handle errors appropriately. Don't assume every request will succeed.
if (response.StatusCode == HttpStatusCode.NotFound)
{
Console.WriteLine("Customer not found");
}
else if (response.StatusCode == HttpStatusCode.Unauthorized)
{
Console.WriteLine("Authentication failed - check your token");
}
3. Use Appropriate HTTP Verbs
Use the correct HTTP verb for each operation:
- GET for reading data (never use GET to modify data)
- POST for creating new resources
- PUT for updating existing resources
- DELETE for removing resources
4. Include Proper Headers
Always include appropriate headers:
Content-Type: application/json- When sending JSON dataAccept: application/json- When you want JSON responsesAuthorization: Bearer {token}- For authentication
5. Validate Input Data
Before sending data to an API, validate it on your end to catch errors early:
- Check that required fields are present
- Verify email addresses are in correct format
- Ensure numeric fields contain numbers
- Check that IDs exist before trying to update or delete
6. Read the API Documentation
Every API is slightly different. Always read the official documentation to understand:
- What endpoints are available
- What parameters are required vs. optional
- What format the data should be in
- What response codes to expect
- Rate limits and usage restrictions
Common Mistakes to Avoid
❌
GET /customers/12345/delete✓
DELETE /customers/12345GET requests should never modify data - they're for reading only.
Always check the status code. A 404 means the resource wasn't found, not that the request succeeded.
Most APIs require authentication. If you get a 401 Unauthorized error, check your bearer token.
Networks can fail. Always wrap API calls in try-catch blocks to handle timeouts and connection errors.
Never hardcode API keys, tokens, or passwords in your source code. Use environment variables or configuration files.
Summary
- REST APIs allow programs to communicate over HTTP using standard methods
- Collections are groups of items (e.g., /customers), objects are specific items (e.g., /customers/12345)
- HTTP Verbs correspond to actions: GET (read), POST (create), PUT (update), DELETE (delete)
- CRUD operations map directly to HTTP verbs
- Status codes tell you if the request succeeded (2xx), had a client error (4xx), or had a server error (5xx)
- JSON is the most common format for sending and receiving data
- Authentication (usually via Bearer token) is required for most API operations
With this understanding, you can start exploring and using REST APIs in your applications. Remember to always read the specific API's documentation, as each API may have its own unique requirements and conventions.