114 lines
3.2 KiB
Markdown
114 lines
3.2 KiB
Markdown
|
# Fenceless Grazing System API Server
|
||
|
|
||
|
This is the repository for the API server component of the Fenceless
|
||
|
Grazing System. This server is written in Python using the Flask
|
||
|
microframework, and uses the SQLAlchemy ORM to interact with the SQLite
|
||
|
database.
|
||
|
|
||
|
## Getting the Dependencies
|
||
|
|
||
|
The API server depends on several packages to operate properly, which
|
||
|
will likely not be installed by default on your system. There are two
|
||
|
ways to get the required dependencies: using Python's
|
||
|
`virtualenv` (standard in the Python ecosystem), or using Nix (only if you are into that kind of thing).
|
||
|
|
||
|
### Getting the Dependencies with `virtualenv`
|
||
|
|
||
|
First, create a virtual environment (this only has to be done once):
|
||
|
|
||
|
```Bash
|
||
|
virtualenv venv
|
||
|
```
|
||
|
|
||
|
Once the virtual environment has been created, activate it using the
|
||
|
following command:
|
||
|
|
||
|
```Bash
|
||
|
source venv/bin/activate
|
||
|
```
|
||
|
|
||
|
This effectively creates an independent Python environment, into
|
||
|
which you can install packages without affecting your entire
|
||
|
system. You can now install the packages from the `requirements.txt` file:
|
||
|
|
||
|
```Bash
|
||
|
pip install -r requirements.txt
|
||
|
```
|
||
|
|
||
|
With this, you should have all the necessary dependencies.
|
||
|
|
||
|
### Getting the Dependencies with Nix
|
||
|
|
||
|
Below is the Nix expression I use daily to work on
|
||
|
this application:
|
||
|
|
||
|
```Nix
|
||
|
with import <nixpkgs> {};
|
||
|
|
||
|
mkShell {
|
||
|
buildInputs = [ (python3.withPackages (ps: with ps; [ flask flask_sqlalchemy pyjwt bcrypt geopy pip ])) ];
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Note that some packages (`geopy` in particular) are currently unstable; the expressions from stable Nixpkgs
|
||
|
may not provide a working derivation. When using the `nixpkgs-unstable`, I have no such issues.
|
||
|
|
||
|
## Setting Up
|
||
|
The application requires the `DB_LOC` environment variable to be set to indicate the location
|
||
|
of the database that the server should use:
|
||
|
|
||
|
```Bash
|
||
|
export DB_LOC=database.sqlite
|
||
|
```
|
||
|
|
||
|
Additionally, Flask uses the `FLASK_APP` environment variable to determine the entry point
|
||
|
of a web application
|
||
|
|
||
|
```Bash
|
||
|
# Here, fgs represents the fgs/ directory in the repository's root.
|
||
|
export FLASK_APP=fgs
|
||
|
```
|
||
|
|
||
|
Finally, on first run, you need to create the tables in the application's database.
|
||
|
This can be done as follows:
|
||
|
|
||
|
```Python
|
||
|
flask shell
|
||
|
# Imports, among other things, the db variable, which is the handle for the SQLAlchemy ORM.
|
||
|
from fgs import *
|
||
|
|
||
|
# SQLAlchemy needs to be aware of the various tables in our database
|
||
|
from fgs.model import *
|
||
|
|
||
|
# Creates all tables
|
||
|
db.create_all()
|
||
|
|
||
|
# It also helps to set up a user and a couple of collars:
|
||
|
user = User(username='user', password='password')
|
||
|
collar1 = Collar(name='Sample Collar', active=True)
|
||
|
collar2 = Collar(name='Another Collar', active=True)
|
||
|
|
||
|
# To add the newly created objects to the database, use
|
||
|
# db.session.add and db.session.commit
|
||
|
db.session.add(user)
|
||
|
db.session.add(collar1)
|
||
|
db.session.add(collar2)
|
||
|
db.session.commit()
|
||
|
|
||
|
# You can now press Ctrl-D to exit the Flask shell.
|
||
|
```
|
||
|
|
||
|
Once the database has been created, you can start the server
|
||
|
with:
|
||
|
|
||
|
```Bash
|
||
|
flask run
|
||
|
```
|
||
|
|
||
|
## Next Steps
|
||
|
Once the server is up and running, consider setting up the
|
||
|
[app](https://dev.danilafe.com/CS-46X/app), which is able
|
||
|
interact with this API server. Additionally, check out the
|
||
|
[cow description language](https://dev.danilafe.com/CS-46X/cdl)
|
||
|
if you want to generate mock data for the API server's database.
|