<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Godbless Lucky Osu</title>
    <description>The latest articles on Forem by Godbless Lucky Osu (@osugodbless).</description>
    <link>https://forem.com/osugodbless</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1218059%2Fcac36ac6-effe-40f0-a84d-1f29ef5976aa.jpg</url>
      <title>Forem: Godbless Lucky Osu</title>
      <link>https://forem.com/osugodbless</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/osugodbless"/>
    <language>en</language>
    <item>
      <title>Integrating Python with MySQL Databases: An Introduction and Practical Guide</title>
      <dc:creator>Godbless Lucky Osu</dc:creator>
      <pubDate>Sun, 20 Jul 2025 16:30:52 +0000</pubDate>
      <link>https://forem.com/osugodbless/integrating-python-with-mysql-databases-an-introduction-and-practical-guide-53ao</link>
      <guid>https://forem.com/osugodbless/integrating-python-with-mysql-databases-an-introduction-and-practical-guide-53ao</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Connecting MySQL with Python

&lt;ul&gt;
&lt;li&gt;Installing MySQL&lt;/li&gt;
&lt;li&gt;Installing MySQL Connector/Python&lt;/li&gt;
&lt;li&gt;Establishing an Actual Connection with MySQL Database&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Executing SQL Statements (Working with Cursors)

&lt;ul&gt;
&lt;li&gt;Creating a Cursor Object&lt;/li&gt;
&lt;li&gt;Basic &lt;code&gt;cursor&lt;/code&gt; Usage&lt;/li&gt;
&lt;li&gt;Fetching Data From the Result of SQL Query&lt;/li&gt;
&lt;li&gt;&lt;a href="//#inserting-records-in-tables-using-%20raw%20`cursor.execute()`%20endraw%20"&gt;Inserting Records in Tables Using &lt;code&gt;cursor.execute()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Closing Connection

&lt;ul&gt;
&lt;li&gt;What Happens When Connection Fails&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;MySQL is a very popular relational database management system. Interaction with data is critical for software application and so programming languages need a way to connect to databases and perform various operations on databases (like to store, update, query or delete data in a database).&lt;/p&gt;

&lt;p&gt;We'll be focusing on how to integrate a Python program with MySQL database. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As you go through this article, you'll practically see and learn how you can connect and interact with MySQL from your Python code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To fully understand the tutorials in this article, it is recommended that you have a good understanding of Python concepts like control flows, loops, functions, classes and objects, exception handling, and packages, modules, and &lt;a href="https://pip.pypa.io/en/stable/installation/" rel="noopener noreferrer"&gt;pip&lt;/a&gt; (the package installer for Python).&lt;/p&gt;

&lt;p&gt;Also, if you are new to databases, I wrote an article that provides a simple but comprehensive overview of SQL databases (specifically MySQL). You can check it out &lt;a href="https://dev.to/osugodbless/getting-started-with-databases-sql-mysql-39n5"&gt;here&lt;/a&gt;. It is recommended that you spend sometime understanding SQL databases and SQL basic commands before going further in this article.&lt;/p&gt;




&lt;h2&gt;
  
  
  Connecting MySQL with Python
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Installing MySQL
&lt;/h3&gt;

&lt;p&gt;You can skip this if you already have MySQL installed on your system. However if you do not, then the first requirement here is to actually have the &lt;strong&gt;MySQL Server&lt;/strong&gt; installed on the operating system you are currently working from. The &lt;a href="https://dev.mysql.com/doc/refman/8.4/en/installing.html" rel="noopener noreferrer"&gt;MySQL official documentation&lt;/a&gt; provides a guide on how to do this on various operating systems (Windows, macOS, Linux, Solaris).&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing MySQL Connector/Python
&lt;/h3&gt;

&lt;p&gt;To interact with MySQL database from your Python code, you need a &lt;a href="https://www.dbvis.com/thetable/what-is-a-database-driver-and-how-it-works/" rel="noopener noreferrer"&gt;database driver&lt;/a&gt;. A &lt;a href="https://www.dbvis.com/thetable/what-is-a-database-driver-and-how-it-works/" rel="noopener noreferrer"&gt;database driver&lt;/a&gt; is a software that allows applications to connect and interact with a specific DBMS (Database Management System). The driver translates application requests into a language that the database understands.&lt;/p&gt;

&lt;p&gt;Typically, a database driver is usually obtained as a third-party library/package. The most common and recommended driver for connecting Python to MySQL is &lt;code&gt;mysql-connector-python&lt;/code&gt;. The &lt;code&gt;mysql-connector-python&lt;/code&gt; is a third-party Python library that acts as a bridge between Python and MySQL databases, through which Python can interact with MySQL servers, allowing for the execution of queries, manipulation of data and managing of database objects (like tables).&lt;/p&gt;

&lt;p&gt;The recommended way to install MySQL Connector/Python is with pip package manager. Run the command below in your terminal or command line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;mysql-connector-python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the above command, pip downloads and installs &lt;code&gt;mysql-connector-python&lt;/code&gt; library in your environment — &lt;em&gt;global or &lt;a href="https://www.geeksforgeeks.org/python/python-virtual-environment/" rel="noopener noreferrer"&gt;virtual&lt;/a&gt;&lt;/em&gt;. When installed, it provides a top-level package called &lt;code&gt;mysql&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: When working with Python, setting up a &lt;a href="https://www.geeksforgeeks.org/python/python-virtual-environment/" rel="noopener noreferrer"&gt;virtual environment&lt;/a&gt; is recommended, to isolate your work/project from the system's global Python installation and other virtual environments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you have the &lt;code&gt;mysql-connector-python&lt;/code&gt; library installed, you are now ready to use its packages and modules in your Python program.&lt;/p&gt;

&lt;h3&gt;
  
  
  Establishing an Actual Connection with MySQL Database
&lt;/h3&gt;

&lt;p&gt;The first step to take when you want to interact with a MySQL server is to establish a connection with it. To connect, you need to import the &lt;strong&gt;mysql.connector&lt;/strong&gt; package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mysql.connector&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package contains modules like &lt;strong&gt;connection&lt;/strong&gt;, &lt;strong&gt;errors&lt;/strong&gt;, &lt;strong&gt;errorcode&lt;/strong&gt;, etc. The connection module houses the &lt;code&gt;connect()&lt;/code&gt; method that is used to establish a connection to a MySQL database server.&lt;/p&gt;

&lt;p&gt;The connect() method (function) needs three important parameters to establish a connection. It takes these parameters and returns a MySQLConnection object.  These three parameters are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;host&lt;/code&gt; — host represents the server name or ip on which MySQL is running.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user&lt;/code&gt; — user represents the database user we want to use to connect connect and interact with the database.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: By default the username for MySQL database is root. However, in practice, you must avoid using the root user for interactions. This is because using the root user violates the &lt;a href="https://learn.microsoft.com/en-us/entra/identity-platform/secure-least-privileged-access" rel="noopener noreferrer"&gt;principle of least privilege&lt;/a&gt; which is a security risk. It is recommended that you create a custom-user and grant only the permissions required. Then use that custom-user as user in your Python program. This restricts what your program can do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;password&lt;/code&gt; — password is the password of your database (the one you created when installing MySQL server).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;connect()&lt;/strong&gt; method also accepts other parameters but they are optional — like &lt;code&gt;database&lt;/code&gt; which represents the database name you want to connect to.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Important: The errors and errorcode modules in &lt;code&gt;mysql-connector-python&lt;/code&gt; provide structured ways to handle exceptions that may occur during connection or database operations. It is recommended to wrap your database connection code in a &lt;code&gt;try-except&lt;/code&gt; block to gracefully handle any errors.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, let's import the errors and errorcode module&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mysql.connector&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errorcode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's establish a connection to the MySQL server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Connect to MySQL server
&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Create a MySQLConnection object
&lt;/span&gt;    &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;root&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_db&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Handle specific programming-related MySQL errors
&lt;/span&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProgrammingError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;errorcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ER_ACCESS_DENIED_ERROR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Access denied: incorrect username or password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;errorcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ER_BAD_DB_ERROR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Database does not exist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have to replace the connection details with your actual login credentials and database name. The code uses these credentials to try to establish a connection with your MySQL server. If successful, it returns a MySQLConnection object, which is stored in the connection variable. If not successful, the creation of the object fails and an error message is returned. The except block runs and tries to gracefully handle this failure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The database parameter although optional is recommended in most cases as it tells MySQL to immediately switch to that specific database after establishing connection (just like the USE command in SQL).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Make sure to avoid hard-coding your login credentials (username, password, database) directly in your Python script. This is a serious security risk. A more secure way to store sensitive data, is by using environment variables. In Python, the &lt;a href="https://pypi.org/project/python-dotenv/" rel="noopener noreferrer"&gt;python-dotenv&lt;/a&gt; package lets you store environment variables outside your code and load them into your program. This keeps sensitive data out of your script or source code.&lt;/p&gt;

&lt;p&gt;To do this, you must have the &lt;code&gt;python-dotenv&lt;/code&gt; package installed in your development environment. Then create a &lt;code&gt;.env&lt;/code&gt; file in the root directory of your project, and save all your secrets as key-value pairs in it.  See a more elaborate explanation of how to this &lt;a href="https://pypi.org/project/python-dotenv/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's what your code would look when you use &lt;code&gt;dotenv&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mysql.connector&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mysql.connector&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errorcode&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="c1"&gt;# Load environment variables from a .env file
&lt;/span&gt;&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;DB_HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_HOST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;DB_USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_USER&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;DB_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;DB_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Connect to MySQL server
&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Create a MySQLConnection object
&lt;/span&gt;    &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB_NAME&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Handle specific programming-related MySQL errors
&lt;/span&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProgrammingError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;errorcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ER_ACCESS_DENIED_ERROR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Access denied: incorrect username or password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;errorcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ER_BAD_DB_ERROR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Database does not exist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above method is more secure. If all your details are correct and the try block above runs successfully, it'll return the output below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fim7cvx8ac44mju7jeq6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fim7cvx8ac44mju7jeq6a.png" alt="Connection successful" width="800" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If any of your login credential (username or password) is incorrect, the except block runs and you'll get the output below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fui901c8z40fm1uammpj5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fui901c8z40fm1uammpj5.png" alt="Username or password incorrect" width="800" height="40"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, if your credentials are correct but your database name is incorrect, you'll get a different output like the one below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc8kkp5m6fa3ojavlsw3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc8kkp5m6fa3ojavlsw3l.png" alt="Database does not exist error" width="800" height="41"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Executing SQL Statements (Working with Cursors)
&lt;/h2&gt;

&lt;p&gt;To execute SQL query/queries in Python, you'll need to use a cursor, which is an instance of MySQLCursor class A &lt;code&gt;cursor&lt;/code&gt; is an object used to execute SQL statements and retrieve data from a database. It is created after establishing a connection to the MySQL database, like we've done above. To be more exact, the &lt;code&gt;cursor&lt;/code&gt; is created from your database connection object. &lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Cursor Object
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Basic &lt;code&gt;cursor&lt;/code&gt; Usage
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;execute()&lt;/code&gt; method is used to execute queries. You have to provide the query as a string, either passed directly as an argument or stored in a variable first before passing to &lt;code&gt;cursor.execute()&lt;/code&gt;. Once a query is passed to  &lt;code&gt;cursor.execute()&lt;/code&gt;, it is sent to the database engine for execution. See example of passing the query directly below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Create Books table
&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
CREATE TABLE IF NOT EXISTS Books (
    book_id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(130) NOT NULL,
    price DOUBLE,
    publication_date DATE
)
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The more cleaner and readable way to do this is to first store the query as a string in a named variable. Then pass this variable to &lt;code&gt;cursor.execute()&lt;/code&gt;. See how to do this below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Create Books table
&lt;/span&gt;&lt;span class="n"&gt;create_book_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
CREATE TABLE IF NOT EXISTS Books (
    book_id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(130) NOT NULL,
    price DOUBLE,
    publication_date DATE
)
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;create_book_table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, the query is stored in the &lt;strong&gt;create_book_table&lt;/strong&gt; variable. This variable is then passed to cursor.execute() for execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fetching Data From the Result of SQL Query
&lt;/h3&gt;

&lt;p&gt;There are various methods provided by MySQLCursor class, three (3) of which are used to retrieve the result set of a query.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;fetchall()&lt;/code&gt; — This method retrieves/fetches all rows in the result set of the last executed statement, and returns them as a list of tuples. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;fetchone()&lt;/code&gt; — This returns the next row of the result set as a tuple.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;fetchmany(size)&lt;/code&gt; — this returns the next &lt;strong&gt;size&lt;/strong&gt; number of rows. Size here represents the number of rows you want to retrieve. For instance, &lt;code&gt;cursor.fetchmany(4)&lt;/code&gt; will return the next 4 rows from a query result.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alright, as an example let's retrieve the schema information of the &lt;strong&gt;Books&lt;/strong&gt; table we just created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DESCRIBE Books&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the code above is executed, you would receive an output like the one below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hxemzpg0b27450ry1md.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hxemzpg0b27450ry1md.png" alt="fetchall method result" width="654" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The cursor stores the result set for your query temporarily. The fetch methods is how we access the rows from memory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Inserting Records in Tables Using &lt;code&gt;cursor.execute()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Let's insert data (a book) into our &lt;code&gt;Books&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;But before we get into it, remember the &lt;code&gt;Books&lt;/code&gt; table we created has 4 columns, namely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;book_id&lt;/li&gt;
&lt;li&gt;title&lt;/li&gt;
&lt;li&gt;price&lt;/li&gt;
&lt;li&gt;publication_date&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, remember that the &lt;code&gt;book_id&lt;/code&gt; column was defined with the &lt;strong&gt;AUTO_INCREMENT&lt;/strong&gt; attribute when the table was created. Since the &lt;strong&gt;book_id&lt;/strong&gt; column has the &lt;strong&gt;AUTO_INCREMENT&lt;/strong&gt; attribute, you do not need to manually provide a value for it when inserting a new record. This is because, the database will automatically generate and assign the next available integer value for &lt;code&gt;book_id&lt;/code&gt; each time a new row is inserted.&lt;/p&gt;

&lt;p&gt;With these in mind, let's get into it practically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;

&lt;span class="c1"&gt;# Insert a new book into Books table
&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    INSERT INTO Books (title, price, publication_date)
    VALUES (%s, %s, %s)
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Integrating Python with MySQL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;100.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2025&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# commit the changes
&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Data committed successfully&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We imported the date class from the datetime module because the &lt;code&gt;publication_date&lt;/code&gt; column in the &lt;strong&gt;Books&lt;/strong&gt; table is of type &lt;strong&gt;DATE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Also, you may notice a &lt;code&gt;connection.commit()&lt;/code&gt; statement at the end of the code. This is used to &lt;strong&gt;explicitly commit (save) any changes&lt;/strong&gt; made to the database during the current session. In &lt;code&gt;mysql-connector-python&lt;/code&gt;, changes made by operations such as &lt;strong&gt;INSERT&lt;/strong&gt;, &lt;strong&gt;UPDATE&lt;/strong&gt;, or &lt;strong&gt;DELETE&lt;/strong&gt; are not automatically committed. The connector uses transactional behavior by default, meaning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your changes remain pending (in memory only)&lt;/li&gt;
&lt;li&gt;They are not permanently saved to the database until you call commit()&lt;/li&gt;
&lt;li&gt;If an error occurs before committing, you can use rollback() to undo the changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you forget to commit(), the following happens&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changes won't persist in the database&lt;/li&gt;
&lt;li&gt;Once the connection is closed or rolled back, your uncommitted changes are lost.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing Connection
&lt;/h2&gt;

&lt;p&gt;Once you are done working with the database, you must never forget to close the &lt;code&gt;connection&lt;/code&gt; to release the resources used for the connection. Always close your &lt;code&gt;cursor&lt;/code&gt; and &lt;code&gt;connection&lt;/code&gt; to avoid resource leaks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's how to do it&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A cursor leak happens when your program opens a connection or cursor but never closes it. Overtime, it can cause:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;memory exhaustion or resource exhaustion on your system or the database server.&lt;/li&gt;
&lt;li&gt;slower application performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you interact with a database using Python, you create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A connection object (to the database)&lt;/li&gt;
&lt;li&gt;A cursor object (to send SQL statements and retrieve results)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both processes use system and server resources, so you must always make sure to close them.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Happens When Connection Fails
&lt;/h3&gt;

&lt;p&gt;Now, although you can close your cursor and connection with the code above, it is not the recommended way to do it. &lt;/p&gt;

&lt;p&gt;When you look at the code that handles the connection to MySQL server, if &lt;code&gt;mysql.connector.connect()&lt;/code&gt; fails, this is what happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No connection object is created&lt;/li&gt;
&lt;li&gt;Python jumps immediately to the except block&lt;/li&gt;
&lt;li&gt;So cursor and connection do not exist yet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This becomes a problem because, if you try to run the:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you'll get an error like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvig5ax48sv0fsj801wot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvig5ax48sv0fsj801wot.png" alt="NameError" width="681" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To avoid running into an error when trying to close your cursor and connection, it is recommended that you always check if the variables exist in your code and are valid before trying to close them.&lt;/p&gt;

&lt;p&gt;The way I recommended is to use &lt;code&gt;finally&lt;/code&gt; block in &lt;code&gt;try-except-finally&lt;/code&gt; and have your &lt;code&gt;cursor&lt;/code&gt; and &lt;code&gt;connection&lt;/code&gt; variables initialized to None beforehand. &lt;/p&gt;

&lt;p&gt;With this method, even if your &lt;code&gt;try&lt;/code&gt; block fails before creating a connection, &lt;code&gt;finally&lt;/code&gt; will still run. Remember that the &lt;code&gt;finally&lt;/code&gt; block always runs irrespective of whether the prior code was successfully executed or not. And checking if the variable still has the value None or not protects against calling &lt;code&gt;.close()&lt;/code&gt; on a variable that was never defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Safely close cursor and connection if they were created
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_connected&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;connection.is_connected()&lt;/code&gt; ensures connection is still open before closing it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, you learned how to integrate a Python application with a MySQL database using the &lt;code&gt;mysql-connector-python&lt;/code&gt; library. We backed theory with practical examples on how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install and use the mysql-connector-python driver.&lt;/li&gt;
&lt;li&gt;Establish a connection to a MySQL database from Python.&lt;/li&gt;
&lt;li&gt;Use a cursor object to execute SQL statements.&lt;/li&gt;
&lt;li&gt;Create and insert data into a MySQL table using Python.&lt;/li&gt;
&lt;li&gt;Retrieve data using fetchone(), fetchmany(), and fetchall().&lt;/li&gt;
&lt;li&gt;Use connection.commit() to persist changes.&lt;/li&gt;
&lt;li&gt;Handle potential database errors using try-except with errors and errorcode.&lt;/li&gt;
&lt;li&gt;Properly close your cursor and connection to avoid resource leaks&lt;/li&gt;
&lt;li&gt;Safely clean up connections using finally and None checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Putting it all together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mysql.connector&lt;/span&gt;                                  &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mysql.connector&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errorcode&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;

&lt;span class="c1"&gt;# Load environment variables from a .env file
&lt;/span&gt;&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;DB_HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_HOST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;DB_USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_USER&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;DB_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;DB_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DB_NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize connection and cursor
&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="c1"&gt;# Connect to MySQL server and execute queries
&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Create a MySQLConnection object
&lt;/span&gt;    &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB_NAME&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Create a cursor object
&lt;/span&gt;        &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# Variable store for SQL query
&lt;/span&gt;        &lt;span class="n"&gt;create_book_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        CREATE TABLE IF NOT EXISTS Books (
            book_id INT AUTO_INCREMENT PRIMARY KEY,
            title VARCHAR(130) NOT NULL,
            price DOUBLE,
            publication_date DATE
        )
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

        &lt;span class="c1"&gt;# Create the Books table
&lt;/span&gt;        &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;create_book_table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Get Books table schema (columns define in the Books table)
&lt;/span&gt;        &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DESCRIBE Books&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Insert a new book into Books table
&lt;/span&gt;        &lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
            INSERT INTO Books (title, price, publication_date)
            VALUES (%s, %s, %s)
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Integrating Python with MySQL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;100.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2025&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# commit the changes
&lt;/span&gt;        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Data committed successfully&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Retrieve all records in the Books table
&lt;/span&gt;        &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM Books&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Handle specific programming-related MySQL errors during connection
&lt;/span&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProgrammingError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;errorcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ER_ACCESS_DENIED_ERROR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Access denied: incorrect username or password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;errorcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ER_BAD_DB_ERROR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Database does not exist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Safely close cursor and connection if they were created
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_connected&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, you would most likely be using version control during development, so make sure to add &lt;code&gt;.env&lt;/code&gt; to your &lt;strong&gt;.gitignore&lt;/strong&gt;. This is to ensure that you do not mistakenly commit and push &lt;code&gt;.env&lt;/code&gt; (which contains sensitive information) to version control platforms like GitHub. Pushing your secrets to version control platforms exposes them to the public.&lt;/p&gt;

</description>
      <category>python</category>
      <category>mysql</category>
      <category>database</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Getting Started with Databases: SQL &amp; MySQL</title>
      <dc:creator>Godbless Lucky Osu</dc:creator>
      <pubDate>Sun, 06 Jul 2025 22:09:59 +0000</pubDate>
      <link>https://forem.com/osugodbless/getting-started-with-databases-sql-mysql-39n5</link>
      <guid>https://forem.com/osugodbless/getting-started-with-databases-sql-mysql-39n5</guid>
      <description>&lt;p&gt;Databases are at the heart of modern software systems. Having an efficient data storage and retrieval mechanism is essential in making sure that that platforms run smoothly. Whether it's an e-commerce platform, a mobile app, or a simple backend system, having an efficient way to store and retrieve data ensures the continued operations of the platform. Most applications would be useless without them.&lt;/p&gt;

&lt;p&gt;This article walks through foundational database concepts using &lt;strong&gt;SQL&lt;/strong&gt; and &lt;strong&gt;MySQL&lt;/strong&gt;, based on my recent learning journey. Alright, let's get into it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is a Database?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;database&lt;/strong&gt; is simply a collection of structured information (or data), typically stored electronically. Software applications generate large amount of data from user inputs (e.g a signup form), manipulation of existing data, etc. Therefore, having an organized way of storing these newly generated information, so that applications can access and retrieve them when needed, is essential.&lt;/p&gt;

&lt;p&gt;This is why a database is important. It lets you arrange information in a structured way, making it easier to work with.&lt;/p&gt;

&lt;p&gt;So in the technology world, a database is just one big central repository for storing data in a structured way that makes it easy for software applications to find and utilize information when needed. This here is the main purpose of a database — to store huge amounts of data for secure and speedy access by other programs.&lt;/p&gt;




&lt;h2&gt;
  
  
  How We Create Databases — Database Management System (DBMS)
&lt;/h2&gt;

&lt;p&gt;If databases exist, then a way through which they are created must also exist right?&lt;/p&gt;

&lt;p&gt;The way we create databases is by the use of something we call a Database Management System (DBMS).&lt;/p&gt;

&lt;p&gt;A Database Management System is simply a software for creating and managing databases. It also enables user to create, query, update, modify, and delete data in a database. Think of it as an interface between you (or your application) and the raw data stored in your storage disk.&lt;/p&gt;

&lt;p&gt;Core responsibilities of a database management system includes but not limited to creating databases and tables, adding, editing, and deleting data via queries, fetching specific data using queries, managing user access, security, backups, recovery, performance, etc.&lt;/p&gt;

&lt;p&gt;A database management system has different components but one important component is the &lt;strong&gt;Storage Engine&lt;/strong&gt;. The Storage Engine is the component responsible for how data is actually stored on disk. It interacts with the underlying file system of the operating system to store and manage data.&lt;/p&gt;

&lt;p&gt;Read more about Database Management System (DBMS) &lt;a href="https://www.geeksforgeeks.org/dbms/introduction-of-dbms-database-management-system-set-1/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of Databases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Relational Databases
&lt;/h3&gt;

&lt;p&gt;Relational databases (also called SQL databases) store and organize information into tables with rows (also called tuples) and columns (attributes). Relational (SQL) databases enforce a strict schema, meaning that the structure of the data (tables, columns, and data types) must be defined in advance. In a relational database, different tables have relationships between them (there is a link to explore what relationships are in SQL). These relationships are formed or established using &lt;a href="https://www.techopedia.com/definition/5547/primary-key" rel="noopener noreferrer"&gt;primary keys&lt;/a&gt; and &lt;a href="https://www.techopedia.com/definition/7272/foreign-key" rel="noopener noreferrer"&gt;foreign keys&lt;/a&gt;. Relational databases are very well suited for systems that require data integrity and complex querying such as financial systems.&lt;/p&gt;

&lt;p&gt;Talking about querying, relational databases support a language called &lt;strong&gt;Structured Query Language (SQL)&lt;/strong&gt; for querying and manipulating data. &lt;/p&gt;

&lt;p&gt;Some widely used database management systems that can be used for creating and managing relational databases include &lt;strong&gt;MySQL, MariaDB, PostgreSQL, Oracle&lt;/strong&gt;. Each of these systems supports structured data stored in rows and columns, enforces relationships between tables, and uses SQL for interacting with the data. However, each has its own unique strengths and ideal use cases.&lt;/p&gt;




&lt;h3&gt;
  
  
  Must-Know Relational Database Concepts
&lt;/h3&gt;

&lt;p&gt;Now, in a bid to keep this article as concise as possible, I’ll simply list these concepts as links so you can explore each one in more detail.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.techopedia.com/definition/1242/schema" rel="noopener noreferrer"&gt;Schema&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techopedia.com/definition/1247/table" rel="noopener noreferrer"&gt;Table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techopedia.com/definition/4425/database-row" rel="noopener noreferrer"&gt;Row&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techopedia.com/definition/8/database-column" rel="noopener noreferrer"&gt;Column&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techopedia.com/definition/24438/relationship-databases" rel="noopener noreferrer"&gt;Relationship&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techopedia.com/definition/5547/primary-key" rel="noopener noreferrer"&gt;Primary Key&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techopedia.com/definition/7272/foreign-key" rel="noopener noreferrer"&gt;Foreign Key&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Non Relational Databases(or NoSQL Databases)
&lt;/h3&gt;

&lt;p&gt;Relational databases have certain limitations e.g., they are not (or rather less) useful for storing unstructured data and are generally difficult to scale. &lt;strong&gt;Non relational databases&lt;/strong&gt; in contrast are designed to handle unstructured and semi-structured data and are designed to scale horizontally.&lt;/p&gt;

&lt;p&gt;Think of Non Relational Database (or NoSQL Database) as an umbrella term, that covers the different database models that typically do not implement SQL for defining or querying data. Each database model that does not support SQL have significant difference between them, but they are all collectively referred to as non relational database. Example, MongoDB (a non relational database) store data in the form of JSON-like documents, but Amazon DynamoDB (also a non relational database) store data as a collection of key-value pairs. They both differ significantly from each other but are both referred to as non relational or NoSQL database (simply because they do not use SQL for querying and manipulating data)&lt;/p&gt;

&lt;p&gt;Popular examples of database management systems that can be used for creating and managing NoSQL databases includes &lt;strong&gt;MongoDB, Cassandra, Amazon DynamoDB&lt;/strong&gt;. &lt;br&gt;
NoSQL databases offer scalability, high performance, and are often preferred for big data, real-time applications, and distributed systems.&lt;/p&gt;


&lt;h2&gt;
  
  
  SQL and Common Data Types in SQL
&lt;/h2&gt;

&lt;p&gt;Structured Query Language (SQL) is the standardized language for managing, manipulating, and querying data in relational databases. SQL provides a standardized way to perform various operations on databases.&lt;/p&gt;

&lt;p&gt;Read more about &lt;a href="https://www.techopedia.com/definition/1245/structured-query-language-sql" rel="noopener noreferrer"&gt;SQL here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here are key SQL data types and their uses:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. &lt;strong&gt;Numeric Types&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Used to store numbers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;INT&lt;/code&gt;, &lt;code&gt;SMALLINT&lt;/code&gt;, &lt;code&gt;BIGINT&lt;/code&gt; – Whole numbers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DECIMAL&lt;/code&gt;, &lt;code&gt;NUMERIC&lt;/code&gt; – Precise decimal values&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FLOAT&lt;/code&gt;, &lt;code&gt;DOUBLE&lt;/code&gt; – Floating-point numbers (use with care for precision)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. &lt;strong&gt;Character Types&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Used to store text.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CHAR(n)&lt;/code&gt; – Fixed-length strings&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VARCHAR(n)&lt;/code&gt; – Variable-length strings&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TEXT&lt;/code&gt; – Long-form text&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3. &lt;strong&gt;Date &amp;amp; Time Types&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Used to store temporal values.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DATE&lt;/code&gt; – Stores date only (YYYY-MM-DD)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TIME&lt;/code&gt; – Stores time only (HH:MM:SS)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DATETIME&lt;/code&gt;, &lt;code&gt;TIMESTAMP&lt;/code&gt; – Date and time&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4. &lt;strong&gt;Boolean Type&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Used for logical values.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;BOOLEAN&lt;/code&gt; – Typically when you define a column as &lt;code&gt;BOOLEAN&lt;/code&gt; MySQL automatiocally stored it as &lt;code&gt;TINYINT(1)&lt;/code&gt;. That is &lt;code&gt;BOOLEAN&lt;/code&gt; = &lt;code&gt;TINYINT(1)&lt;/code&gt;. This column takes a BOOLEAN value (TRUE or FALSE) and store it as 0 or 1 (&lt;code&gt;0&lt;/code&gt; for FALSE and &lt;code&gt;1&lt;/code&gt; for TRUE).&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  CHAR vs VARCHAR: What's the Difference?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CHAR(n)&lt;/code&gt; always stores exactly &lt;code&gt;n&lt;/code&gt; characters (space-padded if shorter).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VARCHAR(n)&lt;/code&gt; stores up to &lt;code&gt;n&lt;/code&gt; characters and saves space by only using what's needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use &lt;code&gt;CHAR&lt;/code&gt; when all entries have the same length (e.g., country codes), and &lt;code&gt;VARCHAR&lt;/code&gt; for variable-length text (e.g., names or addresses).&lt;/p&gt;


&lt;h2&gt;
  
  
  SQL Commands You Should Know
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;CREATE&lt;/code&gt; — This is use to create a &lt;strong&gt;new database&lt;/strong&gt; or &lt;strong&gt;new table in a database&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;USE&lt;/code&gt; — This command works a bit like cd in linux. It tells the database management system to navigate and start using the selected database for all commands that would follow. Say we have &lt;strong&gt;database_A&lt;/strong&gt; and &lt;strong&gt;database_B&lt;/strong&gt; already created, and we want to create a table in &lt;strong&gt;database_B&lt;/strong&gt;, how does the database management system know what database to use for creating the table? We'd have to specify what database we want to use for the command we're about to run. The &lt;code&gt;USE&lt;/code&gt; command is how we tell MySQL for example, what database we want to work with.&lt;/p&gt;

&lt;p&gt;Example Use Case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;john_book_store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;USE&lt;/span&gt; &lt;span class="n"&gt;john_book_store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;book_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;130&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ALTER&lt;/code&gt; — The &lt;code&gt;ALTER&lt;/code&gt; command is used to modify an existing table structure. Which means it can be used to add or remove a column in a table.&lt;/p&gt;

&lt;p&gt;Now, let's add a new column (author_id) to our Books table above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="n"&gt;publication_date&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;DROP&lt;/code&gt; — The DROP command deletes an entire existing table or database with all its data. This should be used carefully as any data deleted is permanently lost.&lt;/p&gt;

&lt;p&gt;Now, say we have a table named &lt;strong&gt;Authors&lt;/strong&gt; that hold the information of various authors and we want to delete this entire table, this is how we do it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Authors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;INSERT&lt;/code&gt; — This one is used to add new row(s) into a table.&lt;/p&gt;

&lt;p&gt;Let's add a new book (title = Adventure of John Doe) to the &lt;strong&gt;Books&lt;/strong&gt; table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;publication_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Adventure of John Doe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2025-07-05'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;UPDATE&lt;/code&gt; — I started writing this article yesterday during work period and couldn't finish it. Now if I want to change the &lt;strong&gt;publication_date&lt;/strong&gt; of my book (Adventure of John Doe) which I just added to the Books table, I can do that using the &lt;code&gt;UPDATE&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Let's see how it works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;publication_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2025-07-06'&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;book_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;WHERE&lt;/code&gt; statement is used to filter records. In SQL, it is called a &lt;strong&gt;Clause&lt;/strong&gt; and there are other clauses as well, like &lt;strong&gt;ORDER BY&lt;/strong&gt;, &lt;strong&gt;GROUP BY&lt;/strong&gt;, &lt;strong&gt;JOIN&lt;/strong&gt;, &lt;strong&gt;HAVING&lt;/strong&gt; and some others. Clauses help us control what data should be read or modified and how data retrieved should be presented.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;SELECT&lt;/code&gt; — The &lt;code&gt;SELECT&lt;/code&gt; statement is used to retrieve data from a database table.&lt;br&gt;
For example, say we want to retrieve the title of the book we just added, this is how we can do it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;book_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This tells the database to retrieve only the &lt;code&gt;title&lt;/code&gt; column in the table called Books. The addition &lt;code&gt;WHERE&lt;/code&gt; clause filters the result by telling the database to return the title only for the row where book_id is equal to 1.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;DELETE&lt;/code&gt; — This statement is used to remove a row or multiple row from a database table. Now let's delete the book we just added.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;book_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note that the &lt;code&gt;WHERE&lt;/code&gt; clause is recommended to filter the row or rows to be delete. Without it, all rows in the table will be deleted.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Combining Everything We've Learned: Let's Design an Online Bookstore
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You should have MySQL installed and ready before going further. In case you do not have MySQL installed already, a simple google search should do the trick. There are numerous resources online that you can follow through step-by-step to setup MySQL on whatever Operating System (Windows, MacOS, Linux) you are using.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now let’s see an example of how we might design a simple database for our bookstore:&lt;/p&gt;

&lt;h3&gt;
  
  
  Database Name: &lt;code&gt;john_book_store&lt;/code&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Tables:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Create the database&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;john_book_store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Use the database&lt;/span&gt;
&lt;span class="n"&gt;USE&lt;/span&gt; &lt;span class="n"&gt;john_book_store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Now Let's start creating the schema (tables and their relationships)&lt;/span&gt;

&lt;span class="c1"&gt;-- Create the Authors table&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Authors&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;author_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;author_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;215&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Create the Books table&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;book_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;130&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;author_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="nb"&gt;DOUBLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;publication_date&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;author_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;Authors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;author_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Create the Customers table&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Customers&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;215&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;215&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Create the Orders table&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;order_date&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;Customers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Create the Order_Details table&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Order_Details&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;orderdetailid&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;book_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="nb"&gt;DOUBLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;Specific Explanations&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CREATE DATABASE IF NOT EXISTS john_book_store;&lt;/code&gt; — This whole statement creates a new database named &lt;strong&gt;john_book_store&lt;/strong&gt;, but only if it doesn't already exist. If there's already a database with that name, this line is skipped without error. The next line &lt;strong&gt;USE john_book_store&lt;/strong&gt; will still run successfully, navigating to the existing database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, if you just do &lt;code&gt;CREATE DATABASE john_book_store&lt;/code&gt; and the john_book_store database already exists, then the &lt;code&gt;CREATE DATABASE john_book_store&lt;/code&gt; statement will fail, and your script would produce an error message similar to the one below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp08x85jktg94br7deown.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp08x85jktg94br7deown.png" alt="error-message-database-creation" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I ran into that error while trying to create a database using Python.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;AUTO_INCREMENT&lt;/code&gt; — This tells MySQL to automatically increase count (e.g., 1, 2, 3, ...) with each new row added to the specific column.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;PRIMARY KEY&lt;/code&gt; — You should already be familiar with &lt;code&gt;PRIMARY KEY&lt;/code&gt; if you explored the link I provided at the beginning of this article. This is how to practically implement it. Any column which has been specified as the &lt;code&gt;PRIMARY KEY&lt;/code&gt; provides a way to identify each row in the table.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that it is recommended to define a &lt;code&gt;PRIMARY KEY&lt;/code&gt; for any table you create.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FOREIGN KEY (author_id) REFERENCES Authors(author_id)
);&lt;/code&gt; — This statement sets up a &lt;code&gt;FOREIGN KEY&lt;/code&gt;. That is, it tells the database that &lt;code&gt;author_id&lt;/code&gt; in the &lt;strong&gt;Books&lt;/strong&gt; table must match &lt;code&gt;author_id&lt;/code&gt; in the &lt;strong&gt;Authors&lt;/strong&gt; table.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Understanding databases is really important if you want to build modern applications. Almost every application today uses a database to store, update and retrieve information.&lt;/p&gt;

&lt;p&gt;In this article, we've only explored basic concepts by introducing what databases are, the different types, and dived a bit deeper into SQL and it's basic commands.&lt;/p&gt;

&lt;p&gt;We've only set the ball rolling, you should explore databases more and their use cases (e.g., when to use a SQL database and when NoSQL is ideal).&lt;/p&gt;

&lt;p&gt;I'll be publishing a short article on how to connect Python to a SQL database soon, so watch out for it.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>mysql</category>
      <category>database</category>
      <category>learning</category>
    </item>
    <item>
      <title>CONQUERING THE CLOUD RESUME CHALLENGE: MY JOURNEY</title>
      <dc:creator>Godbless Lucky Osu</dc:creator>
      <pubDate>Fri, 24 May 2024 00:18:51 +0000</pubDate>
      <link>https://forem.com/osugodbless/conquering-the-cloud-resume-challenge-my-journey-1lbe</link>
      <guid>https://forem.com/osugodbless/conquering-the-cloud-resume-challenge-my-journey-1lbe</guid>
      <description>&lt;p&gt;As someone coming from a non-IT background wanting to transition into the IT space and looking to build a career specifically as a DevOps Engineer, I enrolled in an AWS Cloud Computing program, while also taking time to learn other fundamental concepts. Upon completing the program, I successfully passed both the AWS Cloud Practitioner and Solutions Architect - Associate exams, earning both certifications.&lt;/p&gt;

&lt;p&gt;However, I knew certifications were just not enough. I wanted to dive into real projects where I could roll up my sleeves and actually build something using AWS services. To accomplish this, I started looking out for simple projects that I could begin with, however, a friend recommended the Cloud Resume Challenge (although not beginner-friendly) as a great project to explore (and he wasn't wrong😊😊). So, I had a look at it and saw the challenge as an opportunity to bridge the gap between theory and practical experience with the services it covered. Little did I know the adventure that awaited me...&lt;/p&gt;

&lt;p&gt;The cloud resume challenge is actually a challenge by &lt;a href="https://twitter.com/forrestbrazeal" rel="noopener noreferrer"&gt;Forrest Brazeal&lt;/a&gt; to help people prepare for a job in the cloud industry. This post therefore is my way of sharing my experience, challenges, and skills gained during my pursuit of the Cloud Resume Challenge.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find my deployed website &lt;a href="https://osu-resume.com.ng" rel="noopener noreferrer"&gt;here&lt;/a&gt; to explore the project in action. Also, my &lt;a href="https://github.com/osugodbless/cloud-resume-challenge/tree/main" rel="noopener noreferrer"&gt;repository&lt;/a&gt;, which stores all the codes and resources.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Beginning: How I Decided to Tackle the Challenge
&lt;/h2&gt;

&lt;p&gt;Actually, the Cloud Resume Challenge consists of six(6) chunks of work (chunk 0-5) with each chunk consisting of a couple of steps to complete. I tackled the challenge one chunk at a time. Additionally, there are optional "Mods" sections (Developer, DevOps, and Security). Although optional, I decided to tackle the DevOps Mod alongside each chunk of the main challenge. It was an invaluable opportunity to go above and beyond in my pursuit of excellence, and to also expand my understanding of DevOps. I skipped the first chunk (chunk 0) since I already had the requirement——a Cloud Certification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chunk 1: Building the Frontend
&lt;/h2&gt;

&lt;p&gt;Setting up the resume website's frontend seemed straightforward at first. I utilized HTML/CSS to craft a simple site and stored its contents in an S3 bucket. However, I later refined a template from &lt;a href="https://bootstrapmade.com/" rel="noopener noreferrer"&gt;BootstrapMade&lt;/a&gt; and used it instead. I wanted to create a CloudFront distribution to serve the content to viewers globally and even though I had done this before, I decided to read further about CloudFront. This is how I discovered that using a &lt;a href="https://repost.aws/knowledge-center/cloudfront-serve-static-website" rel="noopener noreferrer"&gt;REST API endpoint as the origin&lt;/a&gt;, and restricting access with an &lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html" rel="noopener noreferrer"&gt;Origin Access Control (OAC)&lt;/a&gt; was a more secure way to go about this as opposed to using a website endpoint as the origin (besides, this is AWS's recommended way). You can read about the differences between REST and website API endpoint &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteEndpoints.html#WebsiteRestEndpointDiff" rel="noopener noreferrer"&gt;here&lt;/a&gt;. With the above configuration, I made sure that my website was only accessible via CloudFront, not directly from S3.&lt;/p&gt;

&lt;p&gt;Further to this, I created an SSL/TLS certificate in ACM, and attached it to the CloudFront distribution. This was to ensure that CloudFront uses secure HTTP (HTTPS) to serve the website.&lt;br&gt;
I then configured Amazon Route53 to route traffic from my existing domain to my CloudFront distribution.&lt;/p&gt;

&lt;p&gt;See a screen snip of the website below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjadilt1zfi8mrhdwef7j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjadilt1zfi8mrhdwef7j.png" alt="my website" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  DevOps Way
&lt;/h3&gt;

&lt;p&gt;Lastly, upon verification that &lt;a href="https://osu-resume.com.ng" rel="noopener noreferrer"&gt;my website&lt;/a&gt; was working flawlessly, I decided to do things the DevOps way. I converted the S3, Route53, Certificate Manager and CloudFront resources into code using CloudFormation. Then, I set up a GitHub repository and pushed my website codes and CloudFormation template there.&lt;/p&gt;

&lt;p&gt;See my architectural diagram for the frontend below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxtz1qy3t7ef5hrj8ya27.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxtz1qy3t7ef5hrj8ya27.png" alt="frontend-architecture" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chunk 2 and 3: Tackling the Backend and Testing
&lt;/h2&gt;

&lt;p&gt;As someone with no prior programming experience, Chunk 2 was a tough nut to crack. Most of my time was spent researching, experimenting, and seeking help from online resources and forums (including ChatGPT). I worked with serverless technologies (DynamoDB, Lambda, API Gateway) and built the application using AWS SAM. Everything——from writing the Lambda function using Python, workshopping permissions between Lambda and DynamoDB, to configuring Amazon API Gateway and leveraging JavaScript fetch API to update and retrieve visitor count——felt like a puzzle to solve.&lt;/p&gt;

&lt;p&gt;Another significant challenge I faced was navigating CORS errors and authenticating token issues. After days of persistence, I finally solved the  whole puzzle and had all sevices communicating smoothly.&lt;/p&gt;

&lt;h3&gt;
  
  
  DevOps Way
&lt;/h3&gt;

&lt;p&gt;To wrap up the chunk 2, I set up monitoring for my backend using CloudWatch, Amazon SNS and Lambda. The approach was simple yet effective: I set up CloudWatch Alarms to monitor certain metrics, have notifications sent to my SNS topic when any Alarm enters an alarm state and finally, SNS topic triggers Lambda which in turn extracts the error message from SNS and sends this message to my slack channel, using the slack credentials stored as a parameter in AWS SSM.&lt;/p&gt;

&lt;p&gt;The integration of these tools not only enhanced the resilience of my application but also deepened my understanding of DevOps principles and practices.&lt;/p&gt;

&lt;p&gt;See my architectural diagram for the backend below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsdpfifv5funw1t0h4xy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsdpfifv5funw1t0h4xy.png" alt="backend-architecture" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;I embraced Cypress for writing end-to-end API and website testing. Cypress has good documentation, so it was pretty easy to get around it.&lt;/p&gt;

&lt;p&gt;Conclusively, Chunk 2 especially was a challenging yet rewarding chapter in my Cloud Resume Challenge journey as it helped me gain invaluable insights into backend development and the concept of serverless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chunk 4: CI/CD and Infrastructure as Code
&lt;/h2&gt;

&lt;p&gt;This phase of the project although not less significant, was easier and faster to accomplish. I guess one of the reasons was because I had automated the creation of all resources using CloudFormation and AWS SAM. I did make an adjustment which was to transfer my CloudFormation resources into my AWS SAM template. This was because I found out that AWS SAM supports the syntax of CloudFormation. So, I didn't see the need for having two different templates plus, it helped simplify the build and deploy process.&lt;/p&gt;

&lt;p&gt;I also implemented CI/CD with GitHub Actions. Since I had a single &lt;a href="https://github.com/osugodbless/cloud-resume-challenge/tree/main" rel="noopener noreferrer"&gt;repository&lt;/a&gt; for both backend and frontend, I implemented a multi-job workflow with separate YAML files and both are triggered upon any push to the main branch. One YAML file defines a job that synchronizes website contents to the designated S3 bucket and the other defines a job that builds, deploys, and tests the application built with AWS SAM. I used GitHub's OIDC provider to authenticate to AWS and allow my workflow access to the needed resources in my AWS account. This was to follow security best practice of using temporary credentials for AWS access.&lt;/p&gt;

&lt;p&gt;You can see in the screen snips of both successful jobs below, that the second job includes a step for configuring AWS credentials.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftb9wmnutxmy3immxmr0y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftb9wmnutxmy3immxmr0y.png" alt="s3-sync" width="800" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvnz9fqzuozhj8uik0a5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvnz9fqzuozhj8uik0a5.png" alt="sam-deploy" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringing It All Together
&lt;/h2&gt;

&lt;p&gt;The true magic happened when I pulled down all the application resources and redeployed everything just by pushing a change to my repository. I saw all the pieces converged together to form the complete application. I was very thrilled to see the frontend of my website come to life, seamlessly integrated with backend services and automated testing, without having to spend time manually configuring anything again. It made me trully appreciate the power of automation and CI/CD.&lt;/p&gt;

&lt;p&gt;See the Complete architecture below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbjm1hxa0rvjtpls3wmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbjm1hxa0rvjtpls3wmx.png" alt="cloud-resume-challenge-architectural-diagram" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployed Website
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find my deployed website &lt;a href="https://osu-resume.com.ng" rel="noopener noreferrer"&gt;here&lt;/a&gt; to explore the project in action. Also, my &lt;a href="https://github.com/osugodbless/cloud-resume-challenge/tree/main" rel="noopener noreferrer"&gt;repository&lt;/a&gt;, which stores all the codes and resources.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Lessons Learned and Growth Achieved
&lt;/h2&gt;

&lt;p&gt;Through the Cloud Resume Challenge, I discovered the benefits of automation, version control, CI/CD, monitoring and observability, iteration, continuous learning, and of course the importance of implementing proper application security measures. Each chunk I took and conquered became an opportunity to grow, whether it was troubleshooting errors, reading documentations, getting familiarized with a new technology, or reiterating on the way I went about solving a particular problem. As a result, I've built some invaluable skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking Ahead
&lt;/h2&gt;

&lt;p&gt;After completing the challenge and reflecting on my journey, I realize that the Cloud Resume Challenge is just the beginning. With the newfound skills and confidence I picked, I'm more determined than ever to pursue my goal of becoming an excellent DevOps Engineer. I will be taking time to build my programming skills with Python. In addition, I will be taking on even more projects, starting with a project by &lt;a href="https://linkedin.com/david-thomas-70ba433/" rel="noopener noreferrer"&gt;David Thomas&lt;/a&gt; (&lt;a href="https://pluralsight.com/resources/blog/cloud/cloudguruchallenge-improve-application-performance-using-amazon-elasticache" rel="noopener noreferrer"&gt;Improving application performance using Amazon Elasticache&lt;/a&gt;). The journey would undoubtedly be challenging, but just like the Cloud Resume Challenge, I know the rewards will also be undoubtedly worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;To anyone considering embarking on the Cloud Resume Challenge, my advice is simple: take the leap. As Forrest Brazeal aptly put it, &lt;strong&gt;"It's not a tutorial; it's a project spec."&lt;/strong&gt; And what a project it turned out to be! It's a journey of conquering challenges, unlocking new skills, and discovery of the endless possibilities there are in the Cloud.&lt;/p&gt;

&lt;h3&gt;
  
  
  Collaboration
&lt;/h3&gt;

&lt;p&gt;If you have some cool project and would like some collaboration to learn and tackle it together, you can reach out to me on &lt;a href="https://linkedin.com/in/osugodbless/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;. Let's connect and explore the boundless possibilities of cloud technology, and create innovative solutions together.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>devops</category>
      <category>cloudcomputing</category>
    </item>
    <item>
      <title>Deploy a Static Website Using Amazon S3 (detailed)</title>
      <dc:creator>Godbless Lucky Osu</dc:creator>
      <pubDate>Thu, 18 Apr 2024 15:38:45 +0000</pubDate>
      <link>https://forem.com/osugodbless/deploy-a-static-website-using-amazon-s3-detailed-3hok</link>
      <guid>https://forem.com/osugodbless/deploy-a-static-website-using-amazon-s3-detailed-3hok</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Table of contents&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;INTRODUCTION&lt;/p&gt;

&lt;p&gt;DEPLOY A STATIC WEBSITE ON AMAZON S3&lt;br&gt;
First Task: Creating an S3 bucket to host the static website contents&lt;br&gt;
Second Task: Uploading Source Code to your S3 Bucket&lt;br&gt;
Third Task: Creating a Bucket Policy to Grant Public Read Access&lt;/p&gt;

&lt;p&gt;ENHANCE DATA SECURITY ON AMAZON S3 THROUGH A PROTECTIVE MEASURE: VERSIONING&lt;br&gt;
First Task: Enabling versioning&lt;br&gt;
Second Task: Confirming that versioning works as expected&lt;/p&gt;

&lt;p&gt;OPTIMIZE COSTS OF S3 OBJECT STORAGE BY IMPLEMENTING A COMPREHENSIVE DATA LIFECYCLE PLAN&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;INTRODUCTION&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;One of the simplest architectures that can be implemented on AWS is creating a static website by hosting it entirely on Amazon S3 (Simple Storage Service). It is especially suitable for businesses that want to establish a web presence, showcasing their business details such as location, opening and closing hours, services and products, achievements, testimonials, who they are, etc. Simply put, Amazon S3 in addition to other use cases, can be used to host static websites if you configure the S3 bucket for website hosting. It is important to note, though, that S3 does not support server-side scripting (that is, dynamic websites); however, AWS offers other services that enable you to host dynamic websites.&lt;/p&gt;

&lt;p&gt;S3 is ideal because of the various benefits it offers which include scalability, durability (11 9s of durability), availability (four 9s of availability), fine-grained security and performance.&lt;/p&gt;

&lt;p&gt;In Amazon S3, data files are stored as objects (you can read more about object storage here: &lt;a href="https://cloud.google.com/learn/what-is-object-storage" rel="noopener noreferrer"&gt;cloud.google.com/learn/what-is-object-storage&lt;/a&gt;). Objects are placed in a bucket that you define yourself. The name of your bucket must be globally unique across all AWS Regions. You can store as much objects as you want/need, however, a single/individual object cannot be larger than 5TB.&lt;/p&gt;

&lt;p&gt;To get more details about S3, including its storage classes and storage management, see the Amazon S3 &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html" rel="noopener noreferrer"&gt;Developer Guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moving forward, the content of today’s post will focus on using Amazon Simple Storage Service (Amazon S3) to build a static website and implementing architectural best practices to protect and manage your data.&lt;/p&gt;

&lt;p&gt;Here’s what we’d be doing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Deploy a static website on Amazon S3.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enhance data security on Amazon S3 through a protective measure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optimize Cost by implement a comprehensive data lifecycle plan within Amazon S3.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Alright, let's dive in already!&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;DEPLOY A STATIC WEBSITE ON AMAZON S3&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Before starting, make sure you have all the website codes extracted and ready for uploading. I got the demo code for this from &lt;a href="https://www.free-css.com/free-css-templates/page290/brighton" rel="noopener noreferrer"&gt;free-css.com/free-css-templates/page290/bri..&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To host the static website, we will be &lt;strong&gt;creating an S3 bucket&lt;/strong&gt;, &lt;strong&gt;uploading the code to the bucket&lt;/strong&gt;, and &lt;strong&gt;creating a bucket policy&lt;/strong&gt; to automatically make the website contents publicly accessible on the web even when new changes to codes (i.e. new objects) are uploaded (this is because by default all objects uploaded to an S3 bucket are private).&lt;/p&gt;
&lt;h3&gt;
  
  
  First Task: Creating an S3 bucket to host the static website contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use the search feature in the AWS console, and search for s3. Click on the Create bucket button&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa9q8u1ggtdslfqvwac2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa9q8u1ggtdslfqvwac2b.png" alt="Image description" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Input a unique bucket name (remember that S3 bucket names must be globally unique across all regions). In my own case, I used my name which is globally unique by the way (winks).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select a region to create your bucket. (consider proximity to customers when selecting a region)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8fi3sf1ehnztrlqe8dwe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8fi3sf1ehnztrlqe8dwe.png" alt="Image description" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Disable &lt;strong&gt;Block &lt;em&gt;all&lt;/em&gt; public access&lt;/strong&gt;. You need to allow public access to the S3 bucket containing your website files, if you want your website to be publicly accessible on the internet. Disabling "&lt;strong&gt;Block &lt;em&gt;all&lt;/em&gt; public access&lt;/strong&gt;" ensures that the necessary permissions are set to make your website content publicly readable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on the acknowledgement check button to confirm your agreement.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0kdmeruh706bdkzgo10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0kdmeruh706bdkzgo10.png" alt="Image description" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9esadyvk837jj5mxxrxp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9esadyvk837jj5mxxrxp.png" alt="Image description" width="797" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now, scroll down and click on &lt;strong&gt;Create bucket&lt;/strong&gt;. Congratulations! You just created your bucket successfully.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Now that your bucket has been created, you have to Enable static website hosting on your bucket. Enabling static website hosting provides you with an endpoint URL where customers or the public can access your static website.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;To enable website hosting on your bucket, scroll down in your S3 console. From the list of S3 buckets, select the bucket that you just created (the bucket you’re looking for will ideally carry the unique name you specified during creation).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthwec4xezie197ycjqdn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthwec4xezie197ycjqdn.png" alt="Image description" width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Within the selected bucket, go to the "&lt;strong&gt;Properties&lt;/strong&gt;" tab. This is where you can configure various settings for your S3 bucket.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg1p4duiraayj00enbppx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg1p4duiraayj00enbppx.png" alt="Image description" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Under the properties tab, scroll down to the bottom, and you’ll find &lt;strong&gt;Static Website Hosting&lt;/strong&gt;. Click on &lt;strong&gt;Edit&lt;/strong&gt; in the top-right corner.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq1cdxfaa1rg263b7agtf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq1cdxfaa1rg263b7agtf.png" alt="Image description" width="800" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;enable&lt;/strong&gt;, leave the hosting type as &lt;strong&gt;Host a static website&lt;/strong&gt;, and specify the index document (usually &lt;em&gt;index.html&lt;/em&gt;) and, optionally, the error document.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtigueouoxac9h8d8rwu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtigueouoxac9h8d8rwu.png" alt="Image description" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scroll down and click on &lt;strong&gt;Save changes&lt;/strong&gt;. You now have an endpoint URL where customers can access your static website.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp6n6ll9ci7tt18yjhtb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp6n6ll9ci7tt18yjhtb9.png" alt="Image description" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Second Task: Uploading Source Code to your S3 Bucket
&lt;/h3&gt;

&lt;p&gt;You now need to upload the static website code to S3 bucket&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Navigate back to the "Objects" tab.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on "Upload" to open the file upload interface.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcewi0pgy0xx1v2kiz57.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcewi0pgy0xx1v2kiz57.png" alt="Image description" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;Add files&lt;/strong&gt; to bring up your directories. Navigate to the directory containing the source code files of your static website. This can includes HTML, CSS, JavaScript, images, and others. You can either use the file selection dialog to choose the files, or you can drag and drop them into the upload area.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note: &lt;em&gt;When hosting a static website on Amazon S3, it's important to remember that S3 does not support server-side scripting. Make sure JavaScript included in your files is executed on the client side only. Server-side scripting is not part of S3 functionality and so, would not be processed. For dynamic content, consider using a server-based hosting solution&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zpexvwr53d2imt7pah6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zpexvwr53d2imt7pah6.png" alt="Image description" width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click the orange colour "&lt;strong&gt;Upload&lt;/strong&gt;" button and wait for some seconds/minutes for your files to upload into S3.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mr3spml0susgweqnwf9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mr3spml0susgweqnwf9.png" alt="Image description" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You will see a "&lt;strong&gt;Succeeded&lt;/strong&gt;" status in all your uploads, like the screenshot below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqoryrukme5ygduv7soz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqoryrukme5ygduv7soz.png" alt="Image description" width="800" height="378"&gt;&lt;/a&gt;&lt;br&gt;
Congratulations! You've successfully uploaded your source codes into the S3 bucket.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note: &lt;em&gt;By default, these objects uploaded to the S3 bucket are private, meaning they can only be accessed by you (the AWS account that owns the bucket). To make your static website publicly accessible, you have to configure a bucket policy that grants read access to everyone (public access). This will take us to the third task.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Third Task: Creating a Bucket Policy to Grant Public Read Access
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to the "&lt;strong&gt;Permissions&lt;/strong&gt;" tab and scroll downward to find &lt;strong&gt;Bucket policy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n5k2qxfo6s6c9a1driz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n5k2qxfo6s6c9a1driz.png" alt="Image description" width="643" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the &lt;strong&gt;Edit&lt;/strong&gt; button on the far right of the screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ezymxnfckgteswbyh50.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ezymxnfckgteswbyh50.png" alt="Image description" width="633" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scroll down and click on "&lt;strong&gt;Add new statement&lt;/strong&gt;", you can also find it if you look toward the right of your screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvy44sw0pgoro5sjr2wn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvy44sw0pgoro5sjr2wn.png" alt="Image description" width="764" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6zmf5ydas3r32agtg5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6zmf5ydas3r32agtg5i.png" alt="Image description" width="543" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Locate the &lt;strong&gt;Filter services&lt;/strong&gt; (search bar at the far right of the screen), type in S3 and click on the first option (S3)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wz8s09mi9rj4igb34f0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wz8s09mi9rj4igb34f0.png" alt="Image description" width="467" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scroll down to locate GetObject and click on it.
&amp;gt; &lt;strong&gt;Note: &lt;em&gt;"s3:GetObject" is a permission that grants the right to retrieve objects (files) from the specified S3 bucket.&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxc0wlg4s3hdrhnvl1p6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxc0wlg4s3hdrhnvl1p6.png" alt="Image description" width="324" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add the wildcard "&lt;em&gt;" to the "&lt;/em&gt;&lt;em&gt;Principal&lt;/em&gt;*" in the policy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy your &lt;strong&gt;Bucket ARN&lt;/strong&gt; just above the policy space and paste it in your "&lt;strong&gt;Resource&lt;/strong&gt;." Note that you must add /* just after the pasted policy. The /* means that the policy affects all objects (new and old) in your bucket.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15oqemn1zvrw4h02vekw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15oqemn1zvrw4h02vekw.png" alt="Image description" width="574" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scroll down and click on &lt;strong&gt;Save changes&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your final bucket policy should look like this below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7a9gakm4nndlr7ja21in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7a9gakm4nndlr7ja21in.png" alt="Image description" width="641" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the ARN format for Amazon S3 resources is as follows:&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arn:aws:s3:::bucket_name/object_key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Therefore, your own Bucket ARN would be different. If you are copying this policy, make sure you change the ARN to reflect yours. Read more about adding a bucket policy in S3 &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/add-bucket-policy.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's the JSON code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Statement1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::godbless-v3-s3-bucket/*"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note: This policy grants the "s3:GetObject" permission to everyone ("Principal": "&lt;em&gt;") for all objects in your bucket ("Resource": "arn:aws:s3:::godbless-v3-s3-bucket/&lt;/em&gt;"). This means that anyone can read the objects in your S3 bucket.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Alright, time to get the reward for our hard work so far. Remember the last step in the First Task right? Now is the time to use it. Navigate to the &lt;strong&gt;Properties&lt;/strong&gt; tab again and scroll down to &lt;strong&gt;Static website hosting&lt;/strong&gt;, where you will find your website endpoint (URL).&lt;/p&gt;

&lt;p&gt;Open it in a new browser tab, and if you did everything right, you should find your website application. Congratulations! You just successfully hosted your website and made it publicly accessible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpxxr1ruxz7qli6ozyqq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpxxr1ruxz7qli6ozyqq.png" alt="Image description" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ENHANCE DATA SECURITY ON AMAZON S3 THROUGH A PROTECTIVE MEASURE: VERSIONING
&lt;/h2&gt;

&lt;p&gt;One Amazon S3 best practice is enabling &lt;strong&gt;Versioning&lt;/strong&gt;. It is very likely that you will need to make many updates to your website as a number of things change.&lt;/p&gt;

&lt;p&gt;If you are working with critical data or in collaborative environments where multiple users contribute to data, versioning can help prevent accidental data loss (a strategy to prevent the accidental overwrite and deletion of website objects).&lt;/p&gt;

&lt;p&gt;Versioning keeps multiple versions of an object in the same bucket, preserving, retrieving, and restoring every version. If you delete an object, Amazon S3 inserts a delete marker, making it the current version. You can restore previous versions at any time.&lt;/p&gt;

&lt;p&gt;When you overwrite an object, a new version is created. Buckets can be &lt;strong&gt;unversioned&lt;/strong&gt; (default), &lt;strong&gt;versioning-enabled&lt;/strong&gt;, or &lt;strong&gt;versioning-suspended&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note: Once versioning is enabled, it cannot be changed back to unversioned, but you can suspend versioning on a bucket if needed. Also, enabling versioning can increase storage costs because each version of an object consumes additional storage.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For further information about versioning, see &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/Versioning.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonS3/latest/userguide/Versioning.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alright, now let's dive in already.&lt;/p&gt;

&lt;h3&gt;
  
  
  First Task: Enabling Versioning
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;In the S3 console, navigate to the "&lt;strong&gt;Properties&lt;/strong&gt;" tab, locate Bucket versioning and click on "&lt;strong&gt;Edit&lt;/strong&gt;".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqfjps7u0kqx9sb9s92z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqfjps7u0kqx9sb9s92z.png" alt="Image description" width="680" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the new window, choose &lt;strong&gt;Enable&lt;/strong&gt; and click on &lt;strong&gt;Save changes&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbc5xr7gpnt37og39ztu8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbc5xr7gpnt37og39ztu8.png" alt="Image description" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Versioning has been enabled in your bucket.&lt;/p&gt;

&lt;h3&gt;
  
  
  Second Task: Confirming that Versioning works as expected
&lt;/h3&gt;

&lt;p&gt;Objects in S3 are immutable, meaning that once you upload an object, you cannot modify it directly. Therefore, if you want to make changes to a file, you typically need to make the necessary modifications or updates to the file on your local computer. Then you can upload the modified file back to the S3 bucket, which creates a new version of the object.&lt;/p&gt;

&lt;p&gt;You could change your whole HTML code in your &lt;em&gt;index.html&lt;/em&gt; file, or even your CSS or Javascript code.&lt;/p&gt;

&lt;p&gt;To confirm that versioning has been implemented in this case, we are only going to modify a single line of code in the &lt;em&gt;index.html&lt;/em&gt; file. Let's get started!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make the changes you want to the appropriate file and save it.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note that if you can’t locate the file on your local computer anymore, you can simply download the file from S3 to your local computer and make the changes. To do this, simply navigate to the "&lt;strong&gt;Objects&lt;/strong&gt;" tab, locate the object you want to make changes to (in my case, the index.html file), select it by clicking on the check button, and the download button should come alive. Click on it to download your file. I used the index.html file only as an example here; you can make changes to any file you want.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxut45oshvv9vzxr8fnw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxut45oshvv9vzxr8fnw.png" alt="Image description" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Upload the updated file to your S3 bucket. (I already showed you how to do this in the second task we did when deploying our website).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When your file has been successfully uploaded, go back to the Objects tab and click on "&lt;strong&gt;Show versions&lt;/strong&gt;" as shown below. You should see the current version of your file as well as the previous versions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffavkl7oy6qxp2lxr3e1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffavkl7oy6qxp2lxr3e1v.png" alt="Image description" width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, when you open yoru website, you will notice the changes you made. See the screenshot of mine below. I only made modifications to a single line of code&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2k8igfokydrqrc283d0j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2k8igfokydrqrc283d0j.png" alt="Image description" width="612" height="411"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fip4js6nlhmzdldb3dgzv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fip4js6nlhmzdldb3dgzv.png" alt="Image description" width="639" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  OPTIMIZE COSTS OF S3 OBJECT STORAGE BY IMPLEMENTING A COMPREHENSIVE DATA LIFECYCLE PLAN
&lt;/h2&gt;

&lt;p&gt;When you enable versioning, the size of the S3 bucket will continue to grow as you upload new objects and versions. To save costs, you can choose to implement a strategy to retire some of those older versions.&lt;/p&gt;

&lt;p&gt;Implementing or configuring a &lt;strong&gt;lifecycle policy&lt;/strong&gt; will automatically move older versions of objects between storage classes or Permanently delete previous versions of objects, depending on the action you specify. This cycling reduces your overall cost because you pay less for data as it becomes less important over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A lifecycle configuration is a set of rules that define actions that Amazon S3 applies to a group of objects.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In our case, we are going to configure a policy with two rules. The first rule will move older versions of the objects in our source bucket to S3 Standard-Infrequent Access (S3 Standard-IA) after 30 days (1 month). The second rule will eventually expire the objects after 365 days (a year).&lt;/p&gt;

&lt;p&gt;Let's get started…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to the "&lt;strong&gt;Management&lt;/strong&gt;" tab, locate Lifecycle rules and click on "&lt;strong&gt;Create lifecycle rule&lt;/strong&gt;"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu8ed2uwnltvt6uymhjle.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu8ed2uwnltvt6uymhjle.png" alt="Image description" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the new window, enter your rule name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose the scope of the lifecycle rule. Select "&lt;strong&gt;Apply to all objects in the bucket&lt;/strong&gt;" and click on "&lt;strong&gt;I acknowledge that this rule will apply to all objects in the buckets&lt;/strong&gt;".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28ouy6d4eku7vg657gm0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28ouy6d4eku7vg657gm0.png" alt="Image description" width="799" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If you want to limit the rule to specific objects, then select the first option and specify the object prefix, tag key and value. (in our case, we want the rule to affect all objects in our bucket, which is why we went with the second option).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;To set the first rule which will move older versions of the objects in your source bucket to a different storage class;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Choose "&lt;strong&gt;Move noncurrent versions of objects between storage classes&lt;/strong&gt;".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose your desired storage class. Here we are going with &lt;strong&gt;Standard-IA&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Input the number of days after which older versions of objects will move to the new storage class. (here, I choose 30 days after which objects would move into Standard-IA).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxt0ywoudstayb70qc6i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxt0ywoudstayb70qc6i.png" alt="Image description" width="800" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To set a second rule which will expire the objects after a particular period of time;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scroll back up and select "&lt;strong&gt;Permanently delete noncurrent versions of objects&lt;/strong&gt;".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7ttossdxw3ub4nykwll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7ttossdxw3ub4nykwll.png" alt="Image description" width="800" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scroll down, and you'll see a new rule has appeared, specify the number of days (in our case, we choose 365 days).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl1776p3f4bn94njru7jm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl1776p3f4bn94njru7jm.png" alt="Image description" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scroll down and click on &lt;strong&gt;Create rule&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hurray! You have successfully configured a lifecycle for your objects to manage how they are stored throughout their lifecycle.&lt;/p&gt;

&lt;p&gt;The policy we’ve just set above will move previous versions of your source bucket objects to S3 Standard-IA after 30 days. The policy will also permanently delete the objects that are in S3 Standard-IA after 365 days.&lt;/p&gt;

&lt;p&gt;For more information on Lifecyle Policy, see this &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/user-guide/create-lifecycle.html" rel="noopener noreferrer"&gt;AWS Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  CONCLUSION
&lt;/h2&gt;

&lt;p&gt;We successfully utilized Amazon S3 to host a static website, leveraging its simplicity and scalability. By following the outlined steps, we created an S3 bucket, uploaded the website source code, and configured static website hosting. This approach is particularly advantageous for businesses aiming to establish a web presence and showcase essential information.&lt;/p&gt;

&lt;p&gt;Additionally, we implemented key architectural best practices to enhance data security (Versioning) and optimize costs (Lifecycle policy).&lt;/p&gt;

</description>
      <category>cloudstorage</category>
      <category>aws</category>
      <category>cloudcomputing</category>
      <category>s3</category>
    </item>
  </channel>
</rss>
