Skip to content

oh-crop/back_end

Repository files navigation

OH Crop Logo Build Status Hits Python 3.8.4 Func

Contents

About

Oh Crop! Back-End is an API built using Python and Flask. This API was created to send plant information to the Oh Crop! front end (written in React Native) via RESTful endpoints. You can view the front end repository here. This API uses a PostgreSQL database and has full CRUD functionality for adding plants into gardens. It was built following TDD and agile processes over a period of 14 days, you can view the project board here.

Click here to see the application in use!

Prerequisites

You will need to have the following in order to run this app on your local machine.

Pip 20.1.1
Python3 3.8.4
Flask 1.1.2

Getting Started

Follow the steps below to get you a copy of the project up and running on your local machine for development and testing purposes.

  1. Clone this repo onto your local machine

  2. Run the following commands in your terminal to get the code up and running on your local machine

  • Make sure to run each of these without the $
$ pip install -r requirements.txt
$ alembic upgrade head

Installation

Follow the steps below to view this app locally

Step 1: Start up your virtual environment by running the following command - Make sure you have completed the steps in the getting started section

$ . venv/bin/activate

Step 2: Start the local rails server by running the following command

$ flask run

Step 3: View the website locally by visiting http://localhost:5000/

Note: All of the endpoints in the endpoint section can be run locally

Endpoints

Here are some end points and request response examples to get you started.

GET Endpoints:

Motivational message

This is the home page endpoint with some sample text to ensure that the app is working as expected

https://oh-crop-be.herokuapp.com/api/v1/

All Plants

This endpoint returns all plant object in the database

Request:
https://oh-crop-be.herokuapp.com/api/v1/plants/

Response:
{
    "id": 1,
    "image": "https://skitterphoto.com/photos/skitterphoto-1901-default.jpg"
},
{
    "id": 2,
    "image": "https://cdn.pixabay.com/photo/2019/05/29/19/04/tomatoes-4238247_960_720.jpg"
},
{
    "id": 3,
    "image": "https://live.staticflickr.com/2591/3816942238_e669d597f7_w.jpg"
},
{
    "id": 4,
    "image": "https://storage.needpix.com/rsynced_images/jalapeno-2053130_1280.jpg"
},
{
    "id": 5,
    "image": "https://storage.needpix.com/rsynced_images/dill-2826179_1280.jpg"
},
{
    "id": 6,
...

Meet a Random Plant

This endpoint returns a random plant from the database

Request:
https://oh-crop-be.herokuapp.com/api/v1/plants/meet

Response:
{
    "id": 15,
    "plant_image": "https://c1.peakpx.com/wallpaper/736/669/216/appetite-avacado-avo-avocado-wallpaper-preview.jpg",
    "plant_type": "Avocado"
}

Get Plant by ID (Plant Info)

This endpoint requires an ID to be passed in and it will return information about that plant

Request:
https://oh-crop-be.herokuapp.com/api/v1/plants/2

Response:
{
  "days_between_water": 3,
  "days_to_harvest_from_seed": 50,
  "id": 2,
  "lifecycle": "Perennial",
  "lighting": "Full Sun",
  "plant_image": "https://cdn.pixabay.com/photo/2019/05/29/19/04/tomatoes-4238247_960_720.jpg",
  "plant_type": "Cherry Tomato",
  "root_depth_in": 12
}

Note: Add a plant ID to the end. In the example above the plants ID is 2

Plant Search

This endpoint requires a query parameter of q and will return any plants that even partially match the search term provided. This search is case insensitive.

Request:
https://oh-crop-be.herokuapp.com/api/v1/plants/search?q=tomato

Response:
[
    {
        "id": 1,
        "plant_image": "https://skitterphoto.com/photos/skitterphoto-1901-default.jpg",
        "plant_type": "Better Boy Tomato"
    },
    {
        "id": 2,
        "plant_image": "https://cdn.pixabay.com/photo/2019/05/29/19/04/tomatoes-4238247_960_720.jpg",
        "plant_type": "Cherry Tomato"
    },
    {
        "id": 3,
        "plant_image": "https://live.staticflickr.com/2591/3816942238_e669d597f7_w.jpg",
        "plant_type": "Roma Tomato"
    }
]

Note: will need to pass query params: {q: (search term)}

Note: Search term is not case sensitive and will search within all plant types

Plants in Garden

This endpoint returns all plants you have in your garden, you can use the POST endpoint below to add a plant to your garden

Request:
https://oh-crop-be.herokuapp.com/api/v1/garden

Response:
[
  {
    "id": 32,
    "plant_name": "Regina"
  },
  {
    "id": 33,
    "plant_name": "Hillary"
  },
  {
    "id": 34,
    "plant_name": "Sebastian"
  },
  {
    "id": 35,
    "plant_name": "Arnold"
  }
]

Garden Plant Profile Page

This endpoint returns a show page for a plant that is in your garden. It has specific information about the plant including its name and when it was last watered and when it will be ready to be harvested (if applicable).

Request:
https://oh-crop-be.herokuapp.com/api/v1/garden/plants/5

Response:
{
  "date_added": "Sun, July 26, 2020",
  "days_until_harvest": 74,
  "days_until_next_water": 3,
  "gardenplant_id": 5,
  "harvest_date": "Fri, October 09, 2020",
  "image": "https://live.staticflickr.com/2591/3816942238_e669d597f7_w.jpg",
  "last_watered": "Sun, July 26, 2020",
  "plant_name": "Melissa",
  "plant_type": "Roma Tomato"
}

Note: The ID at the end of this endpoint is the gardenplant id not the plant's id!

POST Endpoints:

Add Plant to Garden

Request:
https://oh-crop-be.herokuapp.com/api/v1/garden?plant_id=4&plant_name=Terry

Response:
{
  "garden_id": 1,
  "garden_plant_id": 10,
  "harvest_date": "Sat, October 24, 2020",
  "plant_id": 4,
  "plant_name": "Terry"
}

Note: will need to pass query params for the ID of the plant being added being added and the unique name the user will assign to the plant: {plant_id: 4, plant_name: Terry}

PUT Endpoints

Water Your Plant

This endpoint allows you to water your plant. It changes the last_watered to today and tells you when you will need to water next

Request:
https://oh-crop-be.herokuapp.com/api/v1/garden/water?garden_plant_id=10

Response:
{
  "id": 10,
  "last_watered": "Sun, July 26, 2020",
  "name": "Terry",
  "next_water": "Tue, July 28, 2020",
  "plant_type": "Jalapeno Peppers",
  "water_frequency": 2
}

DELETE Endpoints:

Delete a plant from your garden

This endpoint allows a user to delete a plant from their garden

https://oh-crop-be.herokuapp.com/api/v1/garden/plants/6

Response:
{
  "gardenplant_id": 7,
  "plant_name": "Tim"
}

Note: will need to pass query params for the ID of the garden_plant (This can be obtained from the id in the add a plant to a garden ednpoint above): {garden_plant_id: 53}

Running the tests

To run the entire test suite on your local machine run the following command

$ pytest

To run a specific test file run the following command

$ python3 <file_path>

Note: Your file path may look something like tests/test_endpoint.py

End to End Testing

These tests were written to check that the API endpoints were working as well as checking that the correct data is returned. Edge cases were also tested, for example we tested that when adding a plant to a garden the date_to_harvest is calculated, but if the plant is not one that can be harvested (ex. a cactus) it should return null.

API Test Example

def test_api_can_add_plant_to_garden(self):
    zeke = Plant(plant_type='Cherry Tomato',image='jim_photo.jpg',lighting='Full Sun',water_frequency=3,harvest_time=50,root_depth=12,annual="Annual")
    agatha = Plant(plant_type='Roma Tomato',image='agatha_photo.jpg',lighting='Full Sun',water_frequency=2,harvest_time=60,root_depth=12,annual="Annual")
    dan = Plant(plant_type='Cactus',image='cactus_dan.jpg',lighting='Full Sun',water_frequency=7,harvest_time=None,root_depth=8,annual="Annual")
    db.session.add_all([zeke, agatha, dan])
    db.session.commit()

    harvest_date = (datetime.now() + timedelta(days=50))
    parsed_harvest_date = harvest_date.strftime("%a, %d %b %Y")
    res = self.client().post('/api/v1/garden?plant_id=1&plant_name=Ezekiel')
    self.assertEqual(res.status_code, 201)
    self.assertIn("Ezekiel", str(res.data))
    self.assertIn("{} 00:00:00 GMT".format(parsed_harvest_date), str(res.data))
def test_api_can_add_plant_to_garden_with_no_harvest_date(self):
    zeke = Plant(plant_type='Cherry Tomato',image='jim_photo.jpg',lighting='Full Sun',water_frequency=3,harvest_time=50,root_depth=12,annual="Annual")
    dan = Plant(plant_type='Cactus',image='cactus_dan.jpg',lighting='Full Sun',water_frequency=7,harvest_time=None,root_depth=8,annual="Annual")
    db.session.add_all([zeke, dan])
    db.session.commit()

    res = self.client().post('/api/v1/garden?plant_id={}&plant_name=Marjorie'.format(dan.id))
    self.assertEqual(res.status_code, 201)
    self.assertIn("Marjorie", str(res.data))
    self.assertIn("null", str(res.data))

Database Layout

Database Layout

Built With

  • Flask - The web framework used
  • SQLAlchemy - The object relational mapper used

Contributors

Back-End Team

Front-End Team

View the Front-End repositoryhere

About

Plant tracking app built in Python/Flask. This is the back end for a React Native front end and is hosted live on Heroku.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages