Free REST API for Testing and Learning

Todo List Fake API for Testing CRUD Operations

A simple and developer-friendly Todo API for practicing REST API workflows like GET, POST, PUT, PATCH, and DELETE. Use it to learn API basics, test apps, build demos, or practice frontend integration with realistic Todo data.

Best for

Students, frontend developers, API beginners, and app prototyping.

Supports

cURL, Fetch, Axios, Python, Ruby on Rails, and Next.js.

Base URL

https://shrimo.com/fake-api/todos

Base URL

https://shrimo.com/fake-api/todos

What is this API for?

Use this API to practice CRUD operations with Todo items. CRUD stands for Create, Read, Update, and Delete.

Quick Test

Send a GET request to https://shrimo.com/fake-api/todos to retrieve a list of Todo items and test your API flow.

Quick start example

Start with a simple GET request to fetch all Todo items. This is the easiest way to confirm the API is working in your app or test environment.

javascript
fetch("https://shrimo.com/fake-api/todos")
  .then((res) => res.json())
  .then((data) => console.log(data));

Todo object schema

Each Todo item includes fields such as title, description, due date, priority, status, and tags. This realistic structure makes it useful for practice apps, dashboards, forms, and table-based UI examples.

json
{
  "id": "672f0dee814c297b16f90093",
  "title": "Learn JavaScript",
  "description": "Complete JavaScript basics",
  "dueDate": "2026-04-20T00:00:00.000Z",
  "priority": "High",
  "status": "Not Started",
  "tags": ["JavaScript", "Learning"],
  "createdAt": "2026-04-15T10:00:00.000Z",
  "updatedAt": "2026-04-15T10:00:00.000Z"
}

API reference

GET/todos

Get all Todo items. Use this for list pages, dashboards, and table views.

GET/todos/:id

Get one Todo by ID. Use this for a detail page or edit form.

POST/todos

Create a new Todo item. Useful for forms and create actions.

PUT/todos/:id

Replace an existing Todo with a full updated version.

PATCH/todos/:id

Update one or more fields on an existing Todo.

DELETE/todos/:id

Delete a Todo item by ID.

GET/todos

Get all todos

What it does: Use GET when you want to read or fetch data.

When to use it: Use this when you want to display all Todo items in a list, table, or dashboard.

Request Body

No request body needed for this method.

Example Response

json
{
  "success": true,
  "count": 2,
  "data": [
    {
      "id": "672f0dee814c297b16f90093",
      "title": "Learn JavaScript",
      "description": "Complete JavaScript basics",
      "dueDate": "2026-04-20T00:00:00.000Z",
      "priority": "High",
      "status": "Not Started",
      "tags": ["JavaScript", "Learning"]
    },
    {
      "id": "672f0dee814c297b16f90094",
      "title": "Build Todo App",
      "description": "Create a practice project",
      "dueDate": "2026-04-22T00:00:00.000Z",
      "priority": "Medium",
      "status": "In Progress",
      "tags": ["Project"]
    }
  ]
}
Simple note: GET requests only read data. They do not create, update, or delete anything.

GET /todos examples by language

cURL

bash
curl -X GET "https://shrimo.com/fake-api/todos"

JavaScript (Fetch)

javascript
const getTodos = async () => {
  const response = await fetch("https://shrimo.com/fake-api/todos");
  const data = await response.json();

  console.log(data);
};

getTodos();

JavaScript (Axios)

javascript
import axios from "axios";

const getTodos = async () => {
  try {
    const response = await axios.get("https://shrimo.com/fake-api/todos");
    console.log(response.data);
  } catch (error) {
    console.error("Error:", error.message);
  }
};

getTodos();

Python

python
import requests

response = requests.get("https://shrimo.com/fake-api/todos")
data = response.json()

print(data)

Ruby on Rails

ruby
require "net/http"
require "uri"
require "json"

uri = URI.parse("https://shrimo.com/fake-api/todos")
response = Net::HTTP.get_response(uri)

if response.is_a?(Net::HTTPSuccess)
  puts JSON.parse(response.body)
else
  puts "Error: #{response.code}"
end

Next.js

javascript
export default async function TodoPage() {
  const res = await fetch("https://shrimo.com/fake-api/todos", {
    cache: "no-store",
  });

  const result = await res.json();

  return (
    <div>
      <h1>All Todos</h1>

      {result.data.map((todo) => (
        <div key={todo.id}>
          <h2>{todo.title}</h2>
          <p>{todo.description}</p>
        </div>
      ))}
    </div>
  );
}
GET/todos/:id

Get one todo by ID

What it does: Use GET with an ID when you want only one item.

When to use it: Use this when you want to open one Todo item and show its details.

Request Body

No request body needed for this method.

Example Response

json
{
  "success": true,
  "count": 1,
  "data": {
    "id": "672f0dee814c297b16f90093",
    "title": "Learn JavaScript",
    "description": "Complete JavaScript basics",
    "dueDate": "2026-04-20T00:00:00.000Z",
    "priority": "High",
    "status": "Not Started",
    "tags": ["JavaScript", "Learning"]
  }
}
Simple note: The ID identifies the exact Todo item you want to retrieve.

GET /todos/:id examples by language

cURL

bash
curl -X GET "https://shrimo.com/fake-api/todos/672f0dee814c297b16f90093"

JavaScript (Fetch)

javascript
const getTodoById = async (id) => {
  const response = await fetch(`https://shrimo.com/fake-api/todos/${id}`);
  const data = await response.json();

  console.log(data);
};

getTodoById("672f0dee814c297b16f90093");

JavaScript (Axios)

javascript
import axios from "axios";

const getTodoById = async (id) => {
  try {
    const response = await axios.get(`https://shrimo.com/fake-api/todos/${id}`);
    console.log(response.data);
  } catch (error) {
    console.error("Error:", error.message);
  }
};

getTodoById("672f0dee814c297b16f90093");

Python

python
import requests

todo_id = "672f0dee814c297b16f90093"
response = requests.get(f"https://shrimo.com/fake-api/todos/{todo_id}")

print(response.json())

Ruby on Rails

ruby
require "net/http"
require "uri"
require "json"

todo_id = "672f0dee814c297b16f90093"
uri = URI.parse("https://shrimo.com/fake-api/todos/#{todo_id}")
response = Net::HTTP.get_response(uri)

if response.is_a?(Net::HTTPSuccess)
  puts JSON.parse(response.body)
else
  puts "Error: #{response.code}"
end

Next.js

javascript
export default async function TodoDetailsPage() {
  const res = await fetch("https://shrimo.com/fake-api/todos/672f0dee814c297b16f90093", {
    cache: "no-store",
  });

  const result = await res.json();
  const todo = result.data;

  return (
    <div>
      <h1>{todo.title}</h1>
      <p>{todo.description}</p>
      <p>Status: {todo.status}</p>
    </div>
  );
}
POST/todos

Create a new todo

What it does: Use POST when you want to create new data.

When to use it: Use this when a user submits a create form or adds a new task.

Request Body

json
{
  "title": "Learn APIs",
  "description": "Practice CRUD methods",
  "dueDate": "2026-04-20",
  "priority": "High",
  "status": "Not Started",
  "tags": ["API", "Practice"]
}

Example Response

json
{
  "success": true,
  "message": "Todo added successfully.",
  "data": {
    "id": "672f0dee814c297b16f90093",
    "title": "Learn APIs",
    "description": "Practice CRUD methods",
    "dueDate": "2026-04-20T00:00:00.000Z",
    "priority": "High",
    "status": "Not Started",
    "tags": ["API", "Practice"]
  }
}
Simple note: POST usually requires a request body containing the new data you want to save.

POST /todos examples by language

cURL

bash
curl -X POST "https://shrimo.com/fake-api/todos" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Learn APIs",
    "description": "Practice CRUD methods",
    "dueDate": "2026-04-20",
    "priority": "High",
    "status": "Not Started",
    "tags": ["API", "Practice"]
  }'

JavaScript (Fetch)

javascript
const createTodo = async () => {
  const response = await fetch("https://shrimo.com/fake-api/todos", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      title: "Learn APIs",
      description: "Practice CRUD methods",
      dueDate: "2026-04-20",
      priority: "High",
      status: "Not Started",
      tags: ["API", "Practice"],
    }),
  });

  const data = await response.json();
  console.log(data);
};

createTodo();

JavaScript (Axios)

javascript
import axios from "axios";

const createTodo = async () => {
  try {
    const response = await axios.post("https://shrimo.com/fake-api/todos", {
      title: "Learn APIs",
      description: "Practice CRUD methods",
      dueDate: "2026-04-20",
      priority: "High",
      status: "Not Started",
      tags: ["API", "Practice"],
    });

    console.log(response.data);
  } catch (error) {
    console.error("Error:", error.message);
  }
};

createTodo();

Python

python
import requests

payload = {
    "title": "Learn APIs",
    "description": "Practice CRUD methods",
    "dueDate": "2026-04-20",
    "priority": "High",
    "status": "Not Started",
    "tags": ["API", "Practice"]
}

response = requests.post("https://shrimo.com/fake-api/todos", json=payload)
print(response.json())

Ruby on Rails

ruby
require "net/http"
require "uri"
require "json"

uri = URI.parse("https://shrimo.com/fake-api/todos")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri.request_uri, {
  "Content-Type" => "application/json"
})

request.body = {
  title: "Learn APIs",
  description: "Practice CRUD methods",
  dueDate: "2026-04-20",
  priority: "High",
  status: "Not Started",
  tags: ["API", "Practice"]
}.to_json

response = http.request(request)
puts JSON.parse(response.body)

Next.js

javascript
async function createTodo() {
  const response = await fetch("https://shrimo.com/fake-api/todos", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      title: "Learn APIs",
      description: "Practice CRUD methods",
      dueDate: "2026-04-20",
      priority: "High",
      status: "Not Started",
      tags: ["API", "Practice"],
    }),
  });

  return response.json();
}
PUT/todos/:id

Replace a todo with PUT

What it does: Use PUT when you want to update an existing item with a full new version.

When to use it: Use this when you want to replace most or all values of an existing Todo item.

Request Body

json
{
  "title": "Learn APIs Better",
  "description": "Practice GET, POST, PUT, PATCH and DELETE",
  "dueDate": "2026-04-25",
  "priority": "Critical",
  "status": "In Progress",
  "tags": ["API", "Study"]
}

Example Response

json
{
  "success": true,
  "message": "Todo updated successfully.",
  "data": {
    "id": "672f0dee814c297b16f90093",
    "title": "Learn APIs Better",
    "description": "Practice GET, POST, PUT, PATCH and DELETE",
    "dueDate": "2026-04-25T00:00:00.000Z",
    "priority": "Critical",
    "status": "In Progress",
    "tags": ["API", "Study"]
  }
}
Simple note: Think of PUT as a full update. It is best when you are sending all major fields again.

PUT /todos/:id examples by language

cURL

bash
curl -X PUT "https://shrimo.com/fake-api/todos/672f0dee814c297b16f90093" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Learn APIs Better",
    "description": "Practice GET, POST, PUT, PATCH and DELETE",
    "dueDate": "2026-04-25",
    "priority": "Critical",
    "status": "In Progress",
    "tags": ["API", "Study"]
  }'

JavaScript (Fetch)

javascript
const updateTodo = async (id) => {
  const response = await fetch(`https://shrimo.com/fake-api/todos/${id}`, {
    method: "PUT",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      title: "Learn APIs Better",
      description: "Practice GET, POST, PUT, PATCH and DELETE",
      dueDate: "2026-04-25",
      priority: "Critical",
      status: "In Progress",
      tags: ["API", "Study"],
    }),
  });

  const data = await response.json();
  console.log(data);
};

updateTodo("672f0dee814c297b16f90093");

JavaScript (Axios)

javascript
import axios from "axios";

const updateTodo = async (id) => {
  try {
    const response = await axios.put(`https://shrimo.com/fake-api/todos/${id}`, {
      title: "Learn APIs Better",
      description: "Practice GET, POST, PUT, PATCH and DELETE",
      dueDate: "2026-04-25",
      priority: "Critical",
      status: "In Progress",
      tags: ["API", "Study"],
    });

    console.log(response.data);
  } catch (error) {
    console.error("Error:", error.message);
  }
};

updateTodo("672f0dee814c297b16f90093");

Python

python
import requests

todo_id = "672f0dee814c297b16f90093"

payload = {
    "title": "Learn APIs Better",
    "description": "Practice GET, POST, PUT, PATCH and DELETE",
    "dueDate": "2026-04-25",
    "priority": "Critical",
    "status": "In Progress",
    "tags": ["API", "Study"]
}

response = requests.put(f"https://shrimo.com/fake-api/todos/{todo_id}", json=payload)
print(response.json())

Ruby on Rails

ruby
require "net/http"
require "uri"
require "json"

todo_id = "672f0dee814c297b16f90093"
uri = URI.parse("https://shrimo.com/fake-api/todos/#{todo_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Put.new(uri.request_uri, {
  "Content-Type" => "application/json"
})

request.body = {
  title: "Learn APIs Better",
  description: "Practice GET, POST, PUT, PATCH and DELETE",
  dueDate: "2026-04-25",
  priority: "Critical",
  status: "In Progress",
  tags: ["API", "Study"]
}.to_json

response = http.request(request)
puts JSON.parse(response.body)

Next.js

javascript
async function updateTodo(id) {
  const response = await fetch(`https://shrimo.com/fake-api/todos/${id}`, {
    method: "PUT",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      title: "Learn APIs Better",
      description: "Practice GET, POST, PUT, PATCH and DELETE",
      dueDate: "2026-04-25",
      priority: "Critical",
      status: "In Progress",
      tags: ["API", "Study"],
    }),
  });

  return response.json();
}
PATCH/todos/:id

Partially update a todo

What it does: Use PATCH when you want to change only one or two fields.

When to use it: Use this when you only want to update status, title, or another small part of the Todo item.

Request Body

json
{
  "status": "Completed"
}

Example Response

json
{
  "success": true,
  "message": "Todo patched successfully.",
  "data": {
    "id": "672f0dee814c297b16f90093",
    "title": "Learn JavaScript",
    "description": "Complete JavaScript basics",
    "dueDate": "2026-04-20T00:00:00.000Z",
    "priority": "High",
    "status": "Completed",
    "tags": ["JavaScript", "Learning"]
  }
}
Simple note: PATCH is ideal for lightweight updates such as changing status from 'In Progress' to 'Completed'.

PATCH /todos/:id examples by language

cURL

bash
curl -X PATCH "https://shrimo.com/fake-api/todos/672f0dee814c297b16f90093" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "Completed"
  }'

JavaScript (Fetch)

javascript
const patchTodo = async (id) => {
  const response = await fetch(`https://shrimo.com/fake-api/todos/${id}`, {
    method: "PATCH",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      status: "Completed",
    }),
  });

  const data = await response.json();
  console.log(data);
};

patchTodo("672f0dee814c297b16f90093");

JavaScript (Axios)

javascript
import axios from "axios";

const patchTodo = async (id) => {
  try {
    const response = await axios.patch(`https://shrimo.com/fake-api/todos/${id}`, {
      status: "Completed",
    });

    console.log(response.data);
  } catch (error) {
    console.error("Error:", error.message);
  }
};

patchTodo("672f0dee814c297b16f90093");

Python

python
import requests

todo_id = "672f0dee814c297b16f90093"

payload = {
    "status": "Completed"
}

response = requests.patch(f"https://shrimo.com/fake-api/todos/{todo_id}", json=payload)
print(response.json())

Ruby on Rails

ruby
require "net/http"
require "uri"
require "json"

todo_id = "672f0dee814c297b16f90093"
uri = URI.parse("https://shrimo.com/fake-api/todos/#{todo_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(uri.request_uri, {
  "Content-Type" => "application/json"
})

request.body = {
  status: "Completed"
}.to_json

response = http.request(request)
puts JSON.parse(response.body)

Next.js

javascript
async function patchTodo(id) {
  const response = await fetch(`https://shrimo.com/fake-api/todos/${id}`, {
    method: "PATCH",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      status: "Completed",
    }),
  });

  return response.json();
}
DELETE/todos/:id

Delete a todo

What it does: Use DELETE when you want to remove data.

When to use it: Use this when a user clicks a delete button and you want to remove the Todo item permanently.

Request Body

No request body needed for this method.

Example Response

json
{
  "success": true,
  "message": "Todo deleted successfully."
}
Simple note: DELETE usually only needs the resource ID in the URL.

DELETE /todos/:id examples by language

cURL

bash
curl -X DELETE "https://shrimo.com/fake-api/todos/672f0dee814c297b16f90093"

JavaScript (Fetch)

javascript
const deleteTodo = async (id) => {
  const response = await fetch(`https://shrimo.com/fake-api/todos/${id}`, {
    method: "DELETE",
  });

  const data = await response.json();
  console.log(data);
};

deleteTodo("672f0dee814c297b16f90093");

JavaScript (Axios)

javascript
import axios from "axios";

const deleteTodo = async (id) => {
  try {
    const response = await axios.delete(`https://shrimo.com/fake-api/todos/${id}`);
    console.log(response.data);
  } catch (error) {
    console.error("Error:", error.message);
  }
};

deleteTodo("672f0dee814c297b16f90093");

Python

python
import requests

todo_id = "672f0dee814c297b16f90093"
response = requests.delete(f"https://shrimo.com/fake-api/todos/{todo_id}")

print(response.json())

Ruby on Rails

ruby
require "net/http"
require "uri"
require "json"

todo_id = "672f0dee814c297b16f90093"
uri = URI.parse("https://shrimo.com/fake-api/todos/#{todo_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Delete.new(uri.request_uri)
response = http.request(request)

puts JSON.parse(response.body)

Next.js

javascript
async function deleteTodo(id) {
  const response = await fetch(`https://shrimo.com/fake-api/todos/${id}`, {
    method: "DELETE",
  });

  return response.json();
}

Status codes made simple

200 OK

The request worked successfully and data was returned.

201 Created

A new Todo item was created successfully.

400 Bad Request

The request body is missing required fields or contains invalid data.

404 Not Found

The Todo item with that ID does not exist.

Best learning order

1. Start with GET /todos

2. Then try POST /todos

3. Then use GET /todos/:id

4. Then learn PUT and PATCH

5. Finally test DELETE /todos/:id

Frequently asked questions

What is a fake API?

A fake API is a sample or mock API used for testing, learning, prototyping, and frontend integration without depending on a live production backend.

Is this Todo API free to use?

Yes. This Todo API is designed for learning, testing, and developer practice.

Can I use this API with React or Next.js?

Yes. You can use this API with React, Next.js, JavaScript Fetch, Axios, Python requests, and other HTTP libraries.

What is the difference between PUT and PATCH?

PUT is generally used to replace the full resource with updated data, while PATCH is used to update only part of a resource, such as just the status field.

Related links

Need this for a real project?

We can help you turn this workflow into a production-ready system.

Tools are useful for quick work, learning, and testing. If you need the same idea inside a real website, dashboard, CRM, portal, API, or business workflow, our team can plan, design, and build it with proper user roles, validation, performance, and long-term support.

Want to learn this properly?

Learn practical web development with guided training.

If you are a student, fresher, or developer building your skills, explore training and internship options instead of only using the tool once.