I have been playing around with ChatGPT for quite some time now and have used it for quite a few things like blog posts, generation of thumbnails, simple programs, random research on certain topics, etc,. Now I wanted to see just how useful ChatGPT can be if I am starting a project from scratch. I started working on this project called Echoes of Eternity. The app sounds very fancy but it’s actually very simple. It can
- Give you a random quote of the day when you access
/qotd
endpoint - List all the quotes that are present in database when you hit
/quotes
endpoint
Let’s dive straight into it. Here goes my first prompt
I need a Go program that will respond to /qotd endpoint with a Quote json. Quote is a struct holding author and a quote.
ChatGPT:
package main
import (
"encoding/json"
"net/http"
)
type Quote struct {
Author string `json:"author"`
Quote string `json:"quote"`
}
func main() {
http.HandleFunc("/qotd", quoteOfTheDay)
http.ListenAndServe(":8080", nil)
}
func quoteOfTheDay(w http.ResponseWriter, r *http.Request) {
quote := Quote{
Author: "Mark Twain",
Quote: "Good friends, good books, and a sleepy conscience: this is the ideal life.",
}
json, err := json.Marshal(quote)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(json)
}
As you can see it knows that qotd is quote of the day and that it will need a Quote struct. Awesome! Now I want quote fetched from database so here goes another prompt
Now update above code to read a random quote from quotes.db
ChatGPT:
func quoteOfTheDay(w http.ResponseWriter, r *http.Request) {
db, err := sql.Open("sqlite3", "quotes.db")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer db.Close()
var count int
err = db.QueryRow("SELECT COUNT(*) FROM quotes").Scan(&count)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
var idx = rand.Intn(count)
var quote Quote
err = db.QueryRow("SELECT author, quote FROM quotes WHERE id = ?", idx).Scan("e.Author, "e.Quote)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json, err := json.Marshal(quote)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(json)
}
The code is syntactically correct but I really don’t want database initialized in my request handler
I would prefer that the database initialization happens in main. Just give me code without the explanation
ChatGPT:
var db *sql.DB
func main() {
var err error
db, err = sql.Open("sqlite3", "quotes.db")
if err != nil {
panic(err)
}
defer db.Close()
http.HandleFunc("/qotd", quoteOfTheDay)
http.ListenAndServe(":8080", nil)
}
It uses the global variable in the handler function. Quite good but I have seen it initializing database without global variable. I actually prefer that way but for now this works.
We need to create quotes.db. Can you provide me with some dummy data for this database
ChatGPT:
CREATE TABLE quotes (id INTEGER PRIMARY KEY, author TEXT, quote TEXT);
INSERT INTO quotes (author, quote) VALUES
("Mark Twain", "Good friends, good books, and a sleepy conscience: this is the ideal life."),
("Albert Einstein", "Imagination is more important than knowledge."),
("Mahatma Gandhi", "Be the change that you wish to see in the world."),
("Steve Jobs", "Your work is going to fill a large part of your life, and the only way to be truly satisfied is to do what you believe is great work. And the only way to do great work is to love what you do. If you haven't found it yet, keep looking. Don't settle. As with all matters of the heart, you'll know when you find it."),
("Henry Ford", "Whether you think you can, or you think you can't - you're right.");
So now our app can at least respond with random quote. Let’s add some more capability to it
Now give me an API that will list all the quotes on certain endpoint
It adds http.HandleFunc("/quotes", listQuotes)
in main and then goes on to give implementation of listQuotes
ChatGPT
func listQuotes(w http.ResponseWriter, r *http.Request) {
rows, err := db.Query("SELECT id, author, quote FROM quotes")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer rows.Close()
var quotes []Quote
for rows.Next() {
var quote Quote
err := rows.Scan("e.ID, "e.Author, "e.Quote)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
quotes = append(quotes, quote)
}
json, err := json.Marshal(quotes)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(json)
}
These are just endpoints we need some front-end to view our quotes
Now give me a HTML homepage that can list all the quotes available at /quotes endpoint
ChatGPT
<html>
<head>
<title>Quotes</title>
</head>
<body>
<h1>Quotes</h1>
<ul id="quote-list"></ul>
<script>
fetch("/quotes")
.then(response => response.json())
.then(quotes => {
const quoteList = document.getElementById("quote-list");
for (const quote of quotes) {
const li = document.createElement("li");
li.innerHTML = `"${quote.quote}" - ${quote.author}`;
quoteList.appendChild(li);
}
});
</script>
</body>
</html>
Along with above HTML the response also included updated Go code to serve above html
http.HandleFunc("/", homepage)
http.HandleFunc("/qotd", quoteOfTheDay)
http.HandleFunc("/quotes", listQuotes)
http.ListenAndServe(":8080", nil)
}
func homepage(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "index.html")
}
Now we can view quotes when we hit our website but still the HTML is too barebones. Let’s stylize it. Below was my prompt
Can you stylize the homepage a little bit? Maybe use card for each quote
It’s initial approach was to use bootstrap and it’s response was truncated so I’m not including it here. I threw another prompt at it
I would prefer not using bootstrap
ChatGPT:
<html>
<head>
<title>Quotes</title>
<style>
.card {
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
overflow: hidden;
}
.card-body {
flex: 1;
padding: 16px;
}
.card-text {
margin: 0;
}
.card-footer {
background-color: #f7f7f7;
border-top: 1px solid #ccc;
padding: 16px;
}
</style>
</head>
<body>
<h1>Quotes</h1>
<div id="quote-list"></div>
<script>
fetch("/quotes")
.then(response => response.json())
.then(quotes => {
const quoteList = document.getElementById("quote-list");
for (const quote of quotes) {
const card = document.createElement("div");
card.className = "card";
card.innerHTML = `
<div class="card-body">
<p class="card-text">"${quote.quote}"</p>
</div>
<div class="card-footer">
<p class="card-text">- ${quote.author}</p>
</div>
`;
quoteList.appendChild(card);
}
});
</script>
</body>
</html>
This was good but I had to do couple of iterations with it to fine tune design of my webpage. I am not going to include all responses but here are all the prompts I used
I would prefer that card does not extend throughout the screen and remains centered. Also, provide me the updated parts of code only and not entire listing
That was incomplete response. I would prefer that you respond with just the changes that are required in code for my previous request
what css I need to update if I want to have spacing between 2 cards
Now I need a good header for this page. You can center the heading and change it to “echoes of eternity”. Stylize the header. You can just provide code related to header
Add some color to header and choose some nice font
The final output
<html>
<head>
<title>Quotes</title>
<style>
.header {
color: #00bfff;
font-family: "Courier New", monospace;
font-size: 32px;
font-weight: bold;
margin: 32px 0;
text-align: center;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.card-wrapper {
display: flex;
flex-wrap: wrap;
justify-content: center;
max-width: 800px;
margin: 0 auto;
}
.card {
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
overflow: hidden;
max-width: 300px;
margin: 16px;
}
.card-body {
flex: 1;
padding: 16px;
}
.card-text {
margin: 0;
}
.card-footer {
background-color: #f7f7f7;
border-top: 1px solid #ccc;
padding: 16px;
}
</style>
</head>
<body>
<h1 class="header">Echoes of Eternity</h1>
<div class="card-wrapper">
<div id="quote-list"></div>
</div>
<script>
fetch("/quotes")
.then(response => response.json())
.then(quotes => {
const quoteList = document.getElementById("quote-list");
for (const quote of quotes) {
const card = document.createElement("div");
card.className = "card";
card.innerHTML = `
<div class="card-body">
<p class="card-text">"${quote.quote}"</p>
</div>
As you can see the response is not complete. But you can get it to do what you want by requesting only the parts of code you are interested in. I have seen it truncating response when the code listing is long. I have observed that this mostly happens with HTML code only. Anyways, entire code listing is available on my GitHub
Except some minor refactoring of code I did not do any changes to the generated code. All of this in under 30 mins and I know just as much CSS as a backend developer would. Here is the screenshot of the app that we designed. It’s very basic but it’s generated by machine!
Subscribe for more!