Coding Without The Traditional Database: Facing The Challenges
Tags: python, tutorial, database, beginners
Published: 2022-08-15 21:32:00

The conventional database would be thought of as the standard tool for building software. Developers like myself frequently ponder whether there is a better approach.

Simply abandoning the common approach and trying something new will result in building without the conventional database. There are several methods, but in our previous [article](https://dev.to/okonkwomandy/python-shelve-or-the-online-database-system-bfd), we chose shelve, a straightforward yet powerful python solution for permanent data storage

I succeeded in creating: [thatnoteapp](http://thatnoteapp.herokuapp.com/). [Thatnoteapp](http://thatnoteapp.herokuapp.com/) is a web app for taking notes that makes use of the shelve package in Python to store notes as private notes. The packages needed for this project are
- UUID
- Flask
- Flask_ckeditor

The major objective of this project was to develop an authentication-free web-based note-taking tool that saves information to the user's device. A website without user registration or login functionality is referred to as authentication-free.

Numerous challenges were faced in the process of developing this project. Some challenges were overcome, and others caused the initial objectives to be adjusted. A few of the issues are shown here, along with solutions.
* Incapable of storing data on the user's device
* Inability to retain new data
* Key error 
* Personalize the data
* Personalize the data: get_data function
* Redirecting the page
* A list or a string

### Incapable of storing data on the user's device
This is a scenario where one's desire to build a program resulted in the creation of something else that was nonetheless beneficial.

The biggest letdown was learning that the website could not access the device's storage as originally intended. To make a folder on the device, I intended on making use of this function.

```
def start():
  folder = os.path.join(Path.home(), '.dais')
  file = os.path.join(folder,'daisdb')
  os.chdir(Path.home())
  if os.path.exists(folder):
    if os.path.exists(file): 
      var = 1
   else:
     os.chdir(folder)
     noteObject = shelve.open('daisdb')
     note = [] 
     noteObject['notes'] = note
     noteObject.close()
   else: 
     os.mkdir('.dais') 
     os.chdir(folder)
     noteObject = shelve.open('daisdb')
     note = [] 
     noteObject['notes'] = note 
     noteObject.close()

```
The functionality had not been created. The server would create the folder rather than the user's device.  This gave me yet another idea: a programmer must always be innovative.

Although creating a folder on the server was sufficient, the objectives needed to be revised. From initially saving the notes on the device, the objective was changed to "building without the traditional database." However, that created a new challenge, which was how to personalize the data without user authentication.

### Inability to retain new data
The list couldn't be updated with the new information. I initially considered making a new list and then rebuilding the shelve data for each newly saved note.

```
noteObject = shelve.open('daisdb', writeback = True)
noteList =  noteObject['notes']
noteList.append(obj)
noteObject['notes'] = noteList
```

Although this method worked, I had to see whether a better solution exist. After considerable investigation, I discovered that the error was generated by my failure to include the write back attribute or close the shelve. To eliminate the mistake, I took this action. 

```
noteObject = shelve.open('daisdb', writeback = True)
 noteObject['notes'].append(obj)
 noteObject.sync() 
noteObject.close()
```

### The key error
```
noteObject.['notes'].append(obj)
```
This would occasionally generate this error and other times it would function as intended.

```
Traceback (most recent call last): File "/usr/lib/python3.5/shelve.py", line 111, in __getitem__ value = self.cache[key] KeyError: 'lb'
```

The Python KeyError, a form of LookupError exception indicates that there was a problem locating the key you were looking for. 

After doing a lot of research and reading StackOverflow, I discovered that the error was triggered by `noteObject['notes']`. The error was eradicated by changing `noteObject['notes']` to `noteObject.get('notes')`

```
noteObject = shelve.open('daisdb', writeback = True) 
noteObject['notes'].append(obj)
```
Changed to

```
noteObject = shelve.open('daisdb', writeback = True)
 noteObject.get('notes').append(obj)
```


### Personalize the data
Utilizing **the IP address** is one method to establish an authentication-free web app.

An IP address, or Internet Protocol address, is a unique series of numbers that identifies any device on a network.

The next step was to obtain the IP addresses from both the **backend (server)** and the **frontend (javascript)** and compare them to generate personalized data.

The server's public IP address, which was not unique, was the IP address that the Python code returned. I required a different IP address for each device, therefore this became a significant issue.

Utilizing [Axios](https://axios-http.com/docs/intro)  to send the IP address to the backend with the newly saved note became the best option.

The `input=hidden` element was used to store before sending the IP address with the submit button 

```
let start = document.getElementById('title')
        start.addEventListener('focus', async() => {
            let result = await axios.get(`https://api.ipify.org?format=json`, {
                mode: 'cors',
                credentials: 'include'
            });

            let data = await result.data;
            document.getElementById('hide').value = data.ip
        })
```
I retrieved the user's IP address from the URL and sent it to a flask view to create a customised page for each user.

```
window.addEventListener('load', async() => { 
 url = "/";
 let result = await axios.get(`https://api.ipify.org?format=json`,
 { mode: 'cors', 
credentials: 'include' 
}); 
 let data = await result.data;  
 let res = axios.post(url, { 
data 
}) 
.then((response) => {
 console.log('sent')
}, (error) => {
 console.log(error);
 });
})
```

### Personalize the data: get_data function
Retrieving data from the backend after utilizing the Axios function to send the data was not familiar to me. It took a lot of research to find out that using the `.get_data()` was the best option.,

The parameter in the function `request.get_data('data')`, is the name of the variable that the data was saved with. 

```
let data = await result.data;  
 let res = axios.post(url, { 
data 
}) 
```
To extract the IP address, the received data is required to be changed into a dictionary.

```
    resp = request.get_data('data')
    
    resp = json.loads(resp.decode("utf-8").replace("'",'"'))

    ipaddress = resp['data']['ip'] 
```

### Redirecting the page
The flask redirect function was ineffective. It appeared to be because an Axios function was used to send the data, so I used Javascript's `window.location.assign()` method to direct the user to their personalized page.

```
window.addEventListener('load', async() => {
    url = "/"

    let result = await axios.get(`https://api.ipify.org?format=json`, {
        mode: 'cors',
        credentials: 'include'
    });

    let data = await result.data;
    console.log(data)
    let res = axios.post(url, {
            data
        })
        .then((response) => {
            window.location.assign('/' + data.ip);
        }, (error) => {
            console.log(error);
        });
})
```
### A list or a string
For some reason, I mistook this `noteObject['notes']` for a string and used a "+" in instead of the list's "append" function. Fortunately, it was resolved very quickly. I suppose when one overthinks, they forget little details. This serves as a reminder that a good programmer should also get enough rest before writing code.



Additionally, there are several things that I figured out rather well. This [link](https://github.com/Mandyiee/thatnoteapp) will take you to the code. As a programmer, I must admit that there are some problems that I haven't solved or whose solutions could be made easier.

Have a thought? Share it below.