Skip to content

Bits of .NET

Daily micro-tips for C#, SQL, performance, and scalable backend engineering.

  • Asp.Net Core
  • C#
  • SQL
  • JavaScript
  • CSS
  • About
  • ErcanOPAK.com
  • No Access
  • Privacy Policy
Ajax

Step-by-Step: Building a CRUD Application with REST API

- 18.08.26 - ErcanOPAK

📋 CRUD App = REST API

CRUD operations are fundamental. Step-by-step guide to build a CRUD application with REST API.

📝 Step 1-4: API Setup

// Step 1: API Service
const API_URL = 'https://jsonplaceholder.typicode.com/posts';

class ApiService {
    static async getPosts() {
        const response = await fetch(API_URL);
        if (!response.ok) throw new Error('Failed to fetch posts');
        return response.json();
    }

    static async createPost(post) {
        const response = await fetch(API_URL, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(post)
        });
        if (!response.ok) throw new Error('Failed to create post');
        return response.json();
    }

    static async updatePost(id, post) {
        const response = await fetch(`${API_URL}/${id}`, {
            method: 'PUT',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(post)
        });
        if (!response.ok) throw new Error('Failed to update post');
        return response.json();
    }

    static async deletePost(id) {
        const response = await fetch(`${API_URL}/${id}`, {
            method: 'DELETE'
        });
        if (!response.ok) throw new Error('Failed to delete post');
        return response;
    }
}

// Step 2: HTML Structure
<div id="app">
    <h1>Posts Management</h1>
    <form id="post-form">
        <input type="text" id="title" placeholder="Title" required>
        <textarea id="body" placeholder="Body" required></textarea>
        <input type="hidden" id="post-id">
        <button type="submit">Add Post</button>
    </form>
    <div id="posts-list"></div>
</div>

📝 Step 5-8: CRUD Operations

// Step 5: Render Posts
async function renderPosts() {
    try {
        const posts = await ApiService.getPosts();
        const container = document.getElementById('posts-list');
        container.innerHTML = posts.map(post => `
            <div class="post-card" data-id="${post.id}">
                <h3>${post.title}</h3>
                <p>${post.body}</p>
                <div class="actions">
                    <button onclick="editPost('${post.id}')">Edit</button>
                    <button onclick="deletePost('${post.id}')">Delete</button>
                </div>
            </div>
        `).join('');
    } catch (error) {
        console.error('Error rendering posts:', error);
    }
}

// Step 6: Create/Update Post
document.getElementById('post-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const title = document.getElementById('title').value;
    const body = document.getElementById('body').value;
    const id = document.getElementById('post-id').value;

    try {
        if (id) {
            await ApiService.updatePost(id, { title, body });
        } else {
            await ApiService.createPost({ title, body, userId: 1 });
        }
        document.getElementById('post-form').reset();
        document.getElementById('post-id').value = '';
        document.querySelector('button[type="submit"]').textContent = 'Add Post';
        await renderPosts();
    } catch (error) {
        console.error('Error saving post:', error);
    }
});

// Step 7: Edit Post
function editPost(id) {
    const post = document.querySelector(`.post-card[data-id="${id}"]`);
    const title = post.querySelector('h3').textContent;
    const body = post.querySelector('p').textContent;
    
    document.getElementById('title').value = title;
    document.getElementById('body').value = body;
    document.getElementById('post-id').value = id;
    document.querySelector('button[type="submit"]').textContent = 'Update Post';
}

// Step 8: Delete Post
async function deletePost(id) {
    if (!confirm('Are you sure you want to delete this post?')) return;
    try {
        await ApiService.deletePost(id);
        await renderPosts();
    } catch (error) {
        console.error('Error deleting post:', error);
    }
}

✅ CRUD App Features

  • ✓ Create posts
  • ✓ Read posts
  • ✓ Update posts
  • ✓ Delete posts
  • ✓ Error handling

Building a CRUD application with REST API is the perfect way to master AJAX. It covers all the essential operations you’ll need.

— Full Stack Developer

Related posts:

Modern Fetch with Async/Await

Ajax: Fix a Loading Spinner That Never Goes Away When a Request Fails Silently

Ajax: Fix a Request Queue That Processes Responses Out of the Order They Were Sent

Post Views: 5

Post navigation

Step-by-Step: Building a Weather App with Fetch API
Entity Framework Core: 10x Performance Boost with AsNoTracking()

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

October 2026
M T W T F S S
 1234
567891011
12131415161718
19202122232425
262728293031  
« Sep    

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (973)
  • How to make theater mode the default for Youtube (952)
  • How to add default value for Entity Framework migrations for DateTime and Bool (939)
  • Get the First and Last Word from a String or Sentence in SQL (847)
  • How to select distinct rows in a datatable in C# (837)
  • How to enable, disable and check if Service Broker is enabled on a database in SQL Server (624)
  • Add Constraint to SQL Table to ensure email contains @ (590)
  • Average of all values in a column that are not zero in SQL (553)
  • How to use Map Mode for Vertical Scroll Mode in Visual Studio (526)
  • Find numbers with more than two decimal places in SQL (468)

Recent Posts

  • CSS: Fix a prefers-color-scheme Media Query That Gets Silently Overridden by a Browser Extension’s Forced Dark Mode
  • Git: Fix a Merge Commit That Silently Drops a File Because Both Branches Deleted It Differently
  • HTML5: Fix a Native Lazy-Loading Image That Never Loads Because It Sits Inside a Hidden Tab Until the User Clicks It
  • The AI Prompt That Traces a Null Reference Exception Back to the Exact Line That First Produced the Null
  • The AI Prompt That Turns a Gym Membership Contract’s Fine Print Into a Plain-English List of Cancellation Steps
  • Photoshop: Fix a Color Profile Mismatch That Makes Printed Output Look Nothing Like What You Saw On Screen
  • WordPress: Fix Search Results That Return Pages From a Theme You Deactivated Months Ago
  • Visual Studio: Fix a Test Project That Builds Fine Alone but Fails to Discover Any Tests After a NuGet Restore
  • ASP.NET Core: Fix a File Upload That Times Out on Slow Connections Only Because Kestrel’s Minimum Data Rate Feature Kicked In
  • JavaScript: Fix an Array Destructuring Default Value That Silently Never Applies Because null Was Passed Instead of Undefined

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (973)
  • How to make theater mode the default for Youtube (952)
  • How to add default value for Entity Framework migrations for DateTime and Bool (939)
  • Get the First and Last Word from a String or Sentence in SQL (847)
  • How to select distinct rows in a datatable in C# (837)

Recent Posts

  • CSS: Fix a prefers-color-scheme Media Query That Gets Silently Overridden by a Browser Extension’s Forced Dark Mode
  • Git: Fix a Merge Commit That Silently Drops a File Because Both Branches Deleted It Differently
  • HTML5: Fix a Native Lazy-Loading Image That Never Loads Because It Sits Inside a Hidden Tab Until the User Clicks It
  • The AI Prompt That Traces a Null Reference Exception Back to the Exact Line That First Produced the Null
  • The AI Prompt That Turns a Gym Membership Contract’s Fine Print Into a Plain-English List of Cancellation Steps

Social

  • ErcanOPAK.com
  • GoodReads
  • LetterBoxD
  • Linkedin
  • The Blog
  • Twitter
© 2026 Bits of .NET | Built with Xblog Plus free WordPress theme by wpthemespace.com