In the previous article I setup a LiteDB (NoSQL database) to my Raspberry Pi. This time I want to add a HTTP listener to my Raspberry Pi that can used to make modifications to the LiteDB database. This will enable me to make changes to the database using Local Area Network (LAN) devices.
I created the example PetWeight class in the repository because I want to have a persistent database for following the weights of several pets. And I'm hoping to create a simple LAN website to control them.
I'll start the development from the "setup" tag of this repository.
To keep the development configurations clean and separate, I decided to leverage the Microsoft.Extensions.Configuration package. I created two configuration files, "appsettings.json" will contain placeholder and default values for the configurations. "appsettings.Development.json" is ignored by git and will need to be created manually, this will override the default values so it can be used safely without pushing the values to git. So lets add the package to our project:
dotnet add package Microsoft.Extensions.Configuration
Kept getting this error after trying to build the project.
error CS1061: 'ConfigurationBuilder' does not contain a definition for 'AddJsonFile' and no accessible extension method 'AddJsonFile' accepting a first argument of type 'ConfigurationBuilder' could be found (are you missing a using directive or an assembly reference?
Turns out the AddJsonFile is included in this package instead. So we will need both.
dotnet add package Microsoft.Extensions.Configuration.Json
I still had one error to solve before I had the appsettings files working. When running the program it was trying to locate the appsettings-files from "bin/Debug/net6.0/appsettings.json". This was fixed by adding a CopyToOutputDirectory to the .csproj-file. It copies the defined file during build to the output folder, which can then be used when running it.
<None Update="appsettings.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> <None Update="appsettings.Development.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None>
I added two settings to our appsettings.json file:
RaspId: Contains the local IP address of the Raspberry Pi
DbPath: Contains the full path to where the database is located
Let's start by adding a HTTP listener to the program. We can remove the hard insert and query from the program and lets create something more general. Lets keep the database and collection as they were. You can of course change the petweights to something more suitable. I separated the class to its own file for clarity.
In the beginning, I want to enable a two basic CRUD operations "Create" and "Read" through the HTTP calls. This way we can insert new entries and check them from the database. The basic CRUD operations are the following, I've included the corresponding HTTP methods.
My first goal is to add an entry to the LiteDB using a POST request. I tested the HTTP listener using the following curl command (using windows CMD).
curl -X POST -H "Content-Type: application/json" -d "{\"Name\":\"Niels\", \"Weight\": 0.5, \"Date\": \"2023-06-23T00:00:00\"}" http://99.99.99.99:5000 # Response <html><body>Inserted Niels to the database</body></html>
We take the request body and create a PetWeight class object from it. This object is saved as a new entry to the database.
I added a handler for the HTTP method of the request. If the method is POST, we try to insert a new entry to the database and if the method is GET, we return all of the entries in the collection.
curl -X GET http://99.99.99.99:5000 # Response <html><body>Pet weighs 1.5 on date 6/17/2023 10:24:21 AM Niels weighs 0.5 on date 6/23/2023 12:00:00 AM </body></html>
That concludes the first part of the HTTP handling for the Raspberry Pi LiteDB. Stay tuned for the followup where we create a simple static website to add entries to the database.
Note: I am aware that the code could be improved, and this is something I plan to address in future iterations or in a separate refactoring process. Currently my focus is on creating a functional foundation rather than a polished end product. As an example, I'm considering managing the different method handlers using a switch statement and function calls in the future and I'm missing error handling.