restgogo-html-template

Go REST API HTML Template File: Undefined API POST Route


When I search for quotes in my database in an admin page through my Go REST API, quotes show up fine with editing fields for their text, author, and category populating. However, the issue is that once I make a change and click the "Update" button, the quote doesn't actually update in the database. At the end of this question, I put what I believe to be the source of the issue, which I'd appreciate help in trying to solve.

The current behaviour is that, let's say I were to change this typo in the following quote to correct "we are challenge to change ourselves" to "we are challenged to change ourselves," the update button presses without error, but when I go to search the same quote again, there was no update applied.

enter image description here

Note that all of these functions are wrapped in a <script> HTML tag in my admin.html.tmpl file:

        function searchQuotes() {
            const keyword = document.getElementById('searchInput').value;
            fetch(`/admin/search/${keyword}`)
                .then(response => response.json())
                .then(quotes => {
                    const searchResultsDiv = document.getElementById('searchResults');
                    searchResultsDiv.innerHTML = ''; // Clear previous search results
                    quotes.forEach(q => {
                        // Create HTML elements to display each quote
                        const quoteDiv = document.createElement('div');
                        quoteDiv.className = 'quote'; // Add class name for styling
                        quoteDiv.dataset.id = q.ID; // Set dataset ID
                        quoteDiv.innerHTML = `
                <input type="text" id="edit_text_${q.ID}" value="${q.text}" />
                <input type="text" id="edit_author_${q.ID}" value="${q.author}" />
                <input type="text" id="edit_classification_${q.ID}" value="${q.classification}" />
                <p>Likes: ${q.likes}</p> <!-- Display the likes count -->
                <button onclick="updateQuote('${q.ID}')" class="update">Update</button>
                <span id="update_status_${q.ID}"></span>
            `;
                        searchResultsDiv.appendChild(quoteDiv);
                    });
                })
                .catch(error => {
                    console.error('Error searching quotes:', error);
                });
        }

        function editQuote(id) {
            // Populate input fields with current quote information
            const text = document.getElementById('edit_text_' + id).value;
            const author = document.getElementById('edit_author_' + id).value;
            const classification = document.getElementById('edit_classification_' + id).value;

            // Set the current quote information to input fields
            document.getElementById('edit_text_' + id).value = text;
            document.getElementById('edit_author_' + id).value = author;
            document.getElementById('edit_classification_' + id).value = classification;
        }

        function updateQuote(id) {
            // Get the edited values
            const editText = document.getElementById('edit_text_' + id).value;
            const editAuthor = document.getElementById('edit_author_' + id).value;
            const editClassification = document.getElementById('edit_classification_' + id).value;

            fetch('/admin/edit/' + id, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    edit_text: editText, // <-- Use 'edit_text' instead of 'text'
                    edit_author: editAuthor, // <-- Use 'edit_author' instead of 'author'
                    edit_classification: editClassification // <-- Use 'edit_classification' instead of 'classification'
                })
            })
                .then(response => {
                    if (response.ok) {
                        // Update UI to signify successful update
                        document.getElementById('update_status_' + id).innerText = '✔ Quote updated';
                    } else {
                        console.error('Failed to update quote');
                    }
                })
                .catch(error => {
                    console.error('Error updating quote:', error);
                });
        }

Now, the following are corresponding Go REST API routes for this functionality:

    // POST /admin/edit/:id - Edit a quote
    r.POST("/admin/edit/:id", func(c *gin.Context) {
        idStr := c.Param("id")
        id, err := strconv.Atoi(idStr)
        if err != nil {
            c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"message": "Invalid quote ID."})
            return
        }

        // Parse the request body into a new quote struct
        var editedQuote quote
        if err := c.ShouldBindJSON(&editedQuote); err != nil {
            c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"message": "Invalid request body."})
            return
        }

        // Check if the edited quote text already exists in the database
        var existingID int
        err = db.QueryRow("SELECT id FROM quotes WHERE text = $1 AND id != $2", editedQuote.EditText, id).Scan(&existingID)
        if err == nil {
            // Edited quote text already exists, return an error
            c.AbortWithStatusJSON(http.StatusConflict, gin.H{"message": "Edited quote text already exists in the database."})
            return
        } else if err != sql.ErrNoRows {
            log.Println(err)
            c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"message": "Failed to check if edited quote already exists in the database."})
            return
        }

        // Update the quote in the database with the edited values
        _, err = db.Exec("UPDATE quotes SET text = $1, author = $2, classification = $3 WHERE id = $4",
            editedQuote.EditText, editedQuote.EditAuthor, editedQuote.EditClassification, id)
        if err != nil {
            log.Println(err)
            c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"message": "Failed to update the quote."})
            return
        }

        c.JSON(http.StatusOK, gin.H{"message": "Quote updated successfully."})
    })

This is the log from when I clicked update, from my API hosting service (Railway):

As you can see, there's definitely an issue with the API route not having the correct quote id, since it's calling this undefined route:

enter image description here


Solution

  • It seems I simply had a mix-up of capitalization here, where I was trying to access q.ID, when it was supposed to be q.id. So, I simply changed this in a few spots of my code to fix my issue.

    Thank you to @Brits for helping me debug by suggesting print statements from the generated HTML:

    <p>ID: ${q.ID}</p> <!-- Display the ID -->
    <p>ID: ${q.id}</p> <!-- Display the ID -->
    

    This is what led to realizing the capitalization mistake, since the latter one printed the correct id value.