Your bar’s new go-to black book solution. Re-sip-e collects and stores your bar’s drink program for seamless connectivity within your team
Organization on GitHub: re-sip-e
Backend Repo: BE
Frontend Repo: FE
Backend Deployed to: Fly.io
Frontend Deployed to: Netlify
- Backend Team
- Frontend Team
This project used Ruby 2.7.4
- with Rails
5.2.x
- and used
PostgreSQL
- Fork this repository
- Clone your fork
- From the command line, install gems and set up your DB:
bundle
- API used
- https://www.thecocktaildb.com
- No API key needed
- Run
rails db:{create,migrate,seed}
- Run the test suite with
bundle exec rspec
.
- If you would like to test the endpoints in
Postman
or app of your choice:- We do have a small seeded DB set up with a bar, a user, and a few drinks with ingredients
- Run your development server with
rails s
to see the app in action - GraphQL Endpoint URL:
http://localhost:3000/graphql
to be used inPostman
- Make sure to put the GraphQL queries/mutations as recommended in the
Body
and withGraphQL
chosen before hittingSend
- You can also test the endpoints in a
GraphiQL
via the BE app being deployed toFly.io
- Go to
https://re-sip-e-be.fly.dev/graphiql
and you wont have to spin up any servers - linked here
- Go to
- Get a Bar's Drinks
- Get A Single Drink
- Get Single API Drink
- Get API Search Result Drinks
- Get Three Random API Drink
- Create a Drink / Save Drink to Database
- Create Drink w/ Errors
- Update Existing Drink
- Update Existing Drink w/ Errors
- Delete a Drink
- Get Bar Info
- Get User Info
Example Query w/ All Available Fields:
query {
drinks(barId: 1) {
id
name
imgUrl
steps
bar {
id
name
}
ingredients {
id
description
}
}
}
Example Response:
{
"data": {
"drinks": [
{
"id": "1",
"name": "Negroni",
"steps": "Stir into glass over ice, garnish and serve.",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/qgdu971561574065.jpg",
"bar": {
"id": "1",
"name": "Joe's Bar"
}
"ingredients": [
{
"id": "5",
"name": "1 oz Gin"
},
{
"id": "8",
"name": "1 oz Campari"
},
**etc...**
]
},
**etc...**
]
}
}
Example Query w/ All Available Fields:
query {
drink(id: 1) {
id
name
imgUrl
steps
bar {
id
name
}
ingredients {
id
description
}
}
}
Example Response:
{
"data": {
"drink": {
"id": "1",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/qgdu971561574065.jpg",
"steps": "Stir into glass over ice, garnish and serve.",
"name": "Negroni",
"ingredients": [
{
"id": "5",
"description": "1 oz Gin"
},
{
"id": "6",
"description": "1 oz Campari",
},
{
"id": "7",
"description": "1 oz Sweet Vermouth"
}
]
}
}
}
Example Query w/ All Available Fields:
query {
apiDrinks(query: "negroni") {
id
name
imgUrl
steps
ingredients {
description
}
}
}
Example Response:
{
"data": {
"apiDrinks": [
{
"id": "11003",
"name": "Negroni",
"steps": "Stir into glass over ice, garnish and serve.",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/qgdu971561574065.jpg",
"ingredients": [
{
"description": "1 oz Gin"
},
{
"description": "1 oz Campari"
},
**etc...**
]
},
**etc...**
]
}
}
Example of Response if Cocktail DB is Provides 4xx or 5xx response error:
{
"data":{
"apiDrinks": null},
"errors": [
{
"message": "the server responded with status 5xx",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [ "apiDrinks" ]
}
]
}
Example Query w/ All Available Fields:
query {
apiDrink(id: 11003){
id
name
steps
imgUrl
ingredients {
description
}
}
}
Example Response:
{
"data": {
"apiDrink": {
"id": "11003",
"name": "Negroni",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/qgdu971561574065.jpg",
"steps": "Stir into glass over ice, garnish and serve.",
"ingredients": [
{
"description": "1 oz Gin"
},
{
"description": "1 oz Campari"
},
{
"description": "1 oz Sweet Vermouth"
}
]
}
}
}
Example of Response if Cocktail DB is Provides 4xx or 5xx response error:
{
"data":{
"apiDrink": null},
"errors": [
{
"message": "the server responded with status 5xx",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [ "apiDrink" ]
}
]
}
Example Query
query {
threeRandomApiDrinks {
id
name
imgUrl
}
}
Example Response:
{
"data": {
"threeRandomApiDrinks": [
{
"id": "178345",
"name": "Hot Toddy",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/ggx0lv1613942306.jpg"
},
{
"id": "17180",
"name": "Aviation",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/trbplb1606855233.jpg"
},
{
"id": "12107",
"name": "Salty Dog",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/4vfge01504890216.jpg"
}
]
}
}
Example of Response if Cocktail DB is Provides 4xx or 5xx response error:
{
"data":{
"threeRandomApiDrinks": null},
"errors": [
{
"message": "the server responded with status 5xx",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [ "threeRandomApiDrinks" ]
}
]
}
Example Mutation with Reponse Returning All Available Fields:
Input JSON Drink Object:
const newDrink = {
"name": "Negroni",
"steps": "Stir into glass over ice, garnish and serve.",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/qgdu971561574065.jpg",
"barId": 1,
"ingredients": [
{
"description": "1 oz Gin"
},
{
"description": "1 oz Campari"
},
{
"description": "1 oz Sweet Vermouth"
}
]
};
GraphQL Variables:
const variables = {
"input":{
"drinkInput": newDrink
}
}
GraphQL Mutation:
mutation($input: DrinkCreateInput!){
drinkCreate(input: $input){
drink{
id
name
steps
imgUrl
ingredients{
id
description
}
}
}
}
Example Response:
{
"data": {
"drinkCreate": {
"drink": {
"id": "3",
"name": "Negroni",
"steps": "Stir into glass over ice, garnish and serve.",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/qgdu971561574065.jpg",
"ingredients": [
{
"id": "5",
"description": "1 oz Gin"
},
{
"id": "6",
"description": "1 oz Campari"
},
{
"id": "7",
"description": "1 oz Sweet Vermouth"
}
]
}
}
}
}
If a given drink object or ingredients does not have the required fields, a response with validation errors will be returned. The following example includes all possible validation errors for drink creation:
{
"data": {
"drinkCreate": null
},
"errors": [
{
"message": "Error creating drink",
"locations": [
{
"line": 34,
"column": 3
}
],
"path": [
"drinkCreate"
],
"extensions": {
"name": [
"can't be blank"
],
"steps": [
"can't be blank"
],
"bar": [
"must exist"
],
"ingredients.description": [
"can't be blank"
]
}
}
]
}
Notes:
- The ID for the drink to be updated should not be passed as part of the drink object. Instead save it as a separate variable and pass it through the base level of the input GQL Variables. See the examples below.
- Ingredients can either be changed, deleted, or added. Ingredient with an ID passed and a
"_destroy": false"
attribute or no"_destroy"
key will be updated. Ingredients with an ID and a"_destroy": true
attribute will be deleted. Ingredients with no id or a null value for ID will create a new ingredient for the drink.
Example Input Object:
const updatedDrinkId = 3
const updatedDrink = {
"name": "Negroni Sbagliato",
"steps": "Stir campari and sweet vermouth into glass over ice, top with proesecco, garnish and serve.",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/qgdu971561574065.jpg",
"ingredients": [
{
"id": "5",
"description": "1 oz Gin",
"_destroy": true
},
{
"id": "6",
"description": "1.5 oz Campari"
},
{
"id": "7",
"description": "1.5 oz Sweet Vermouth"
},
{
"id": null,
"description": "1.5 oz Prosecco"
}
]
}
Example GQL Variables Object:
{
"input": {
"id": udpatedDrinkId,
"drinkInput": updatedDrink
}
}
Example GQL Mutation:
mutation($input: DrinkUpdateInput!){
drinkUpdate(input: $input){
drink{
id
name
steps
imgUrl
ingredients{
id
description
}
}
}
}
Example Response:
{
"data":{
"drinkUpdate": {
"drink":{
"id": "3",
"name": "Negroni Sbagliato",
"steps": "Stir campari and sweet vermouth into glass over ice, top with proesecco, garnish and serve.",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/qgdu971561574065.jpg",
"ingredients": [
{
"id": "6",
"description": "1.5 oz Campari"
},
{
"id": "7",
"description": "1.5 oz Sweet Vermouth"
},
{
"id": "8",
"description": "1.5 oz Prosecco"
}
]
}
}
}
}
If a given drink object or ingredients does not have the required fields on an update, or the drink or ingredient being updated do not exist, a response with validation errors will be returned. The following is an example of an response from an update with invalid validations:
{
"data": {
"drinkUpdate": null
},
"errors": [
{
"message": "Error updating drink",
"locations": [
{
"line": 33,
"column": 3
}
],
"path": [
"drinkUpdate"
],
"extensions": {
"name": [
"can't be blank"
],
"steps": [
"can't be blank"
],
"ingredients.description": [
"can't be blank"
]
}
}
]
}
- Note that at this time there are not possible errors for deleting a drink unless the id provided is not valid.
Example GQL Variables:
{
"input":{
"id": 1
}
}
Example Mutation:
mutation($input: DeleteDrinkInput!){
deleteDrink(input: $input)
){
success
errors
}
}
Example Response:
{
"data": {
"deleteDrink": {
"errors":[],
"success":true
}
}
}
Example Query w/ Available Fields
query {
bar(id: 1) {
id
name
drinkCount
drinks {
id
name
imgUrl
}
}
}
Example Response
{
"data": {
"bar": {
"id": "1",
"name": "Joe's Bar",
"drinkCount": 5,
"drinks": {
"id": "1",
"name": "Negroni",
"imgUrl": "https://www.thecocktaildb.com/images/media/drink/qgdu971561574065.jpg"
},
**etc...**
}
}
}
Example Query w/ Available Fields
query {
user(id: 1) {
id
name
barCount
bars{
id
name
drinkCount
}
}
}
Example Response:
"data": {
"user": {
"id": "1",
"name": "Joe Schmoe",
"barCount": 1,
"bars":[
{
"id": "1",
"name": "Joe's Bar",
"drinkCount": 5
}
]
}
}