{"id":23428573,"url":"https://github.com/rorypoulter/prog-black-web-project","last_synced_at":"2026-04-02T02:50:26.324Z","repository":{"id":267965298,"uuid":"902907065","full_name":"RoryPoulter/Prog-Black-Web-Project","owner":"RoryPoulter","description":"Summative project for Programming Black. Single page express app for a cocktail search engine.","archived":false,"fork":false,"pushed_at":"2025-02-09T17:15:25.000Z","size":103,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-15T07:27:48.967Z","etag":null,"topics":["bootstrap","css","express","html","javascript","nodejs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RoryPoulter.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-13T14:11:58.000Z","updated_at":"2025-02-09T17:13:38.000Z","dependencies_parsed_at":"2024-12-13T16:02:38.399Z","dependency_job_id":"7733dac5-0e77-4598-8534-94bbe71e3521","html_url":"https://github.com/RoryPoulter/Prog-Black-Web-Project","commit_stats":null,"previous_names":["rorypoulter/prog-black-web-project"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoryPoulter%2FProg-Black-Web-Project","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoryPoulter%2FProg-Black-Web-Project/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoryPoulter%2FProg-Black-Web-Project/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoryPoulter%2FProg-Black-Web-Project/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RoryPoulter","download_url":"https://codeload.github.com/RoryPoulter/Prog-Black-Web-Project/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248045269,"owners_count":21038557,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bootstrap","css","express","html","javascript","nodejs"],"created_at":"2024-12-23T07:14:01.109Z","updated_at":"2025-12-30T20:22:42.335Z","avatar_url":"https://github.com/RoryPoulter.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cocktail Search Engine\n![GitHub Release](https://img.shields.io/github/v/release/RoryPoulter/Prog-Black-Web-Project)\n![GitHub License](https://img.shields.io/github/license/RoryPoulter/Prog-Black-Web-Project)\n[![GitHub last commit](https://img.shields.io/github/last-commit/RoryPoulter/Prog-Black-Web-Project.svg?style=flat)]()\n\n### Contents\n- [Usage](#usage)\n  - [Installation](#installation)\n  - [Using the web app](#using-the-web-app)\n- [API Documentation](#api-documentation)\n  - [GET /](#get)\n  - [GET /ingredients](#get-ingredients-returns-json-with-array)\n  - [GET /search](#get-search-returns-json-with-recipes)\n  - [POST /submit](#post-submit)\n  - [DELETE /delete/:recipe](#delete-deleterecipe)\n# Usage\n## Installation\nNavigate to the directory in the terminal and run the command:\n```cmd \nnpm install\n```\nTo test the program runs correctly, run the test cases using:\n```cmd\nnpm test\n```\nIf the program passes all the tests, run the server using:\n```cmd\nnpm start\n```\nOpen your browser and type `127.0.0.1:8080` in the URL bar.\n\n## Using the web app\n### Uploading Recipes\nTo add a new recipe, the following inputs are required:\n* Drink name\n* Drink instructions\n* At least 2 ingredients with measurements\n\nRecipes can have up to 15 ingredients and each must be listed with an amount. The amount of ingredients can be changed by clicking the `+`/`-` buttons.\n\nAn image can be uploaded but is not required; if no image is uploaded, the image below is displayed with the drink instead:\n\n![placeholder image](https://placehold.co/200x200?text=No+Image)\n\nWhen all inputs have been entered, press the `Share` button.\n\nIf the drink name is not unique, or there are missing required inputs, the recipe will not be posted.\n\n### Searching Recipes\nRecipes can be filtered based on if they contain a given ingredient and if the have at most a certain amount of ingredients. To show all recipes, the `ingredient` selection field should be left as `-------` (this does not filter by ingredients), move the slider to the right and click `Search`.\n\nThe order of results can be toggled to be either oldest to newest or vice versa.\n\nIf no recipes match the search criteria, the search results will not change.\n\n\n### Deleting Recipes\nRecipes can be deleted from the API. This can be done by entering the drink name into the form and clicking the `Submit` button. The input is not case sensitive.\n\n# API Documentation\n## \u003cfont color=\"green\"\u003eGET\u003c/font\u003e /\n```\nhttp://127.0.0.1:8080/\n```\nReturns the file `index.html`.\n\n## \u003cfont color=\"green\"\u003eGET\u003c/font\u003e /ingredients\n```\nhttp://127.0.0.1:8080/ingredients\n```\nReturns JSON data with an array of all the ingredients in the drinks. Has no query parameters.\n#### Example Request\n```cmd\ncurl http://127.0.0.1:8080/ingredients\n```\n#### Response\n```JSON\n{\n  \"ingredients\": [\n    \"vodka\",\n    \"orange juice\",\n    \"gin\",\n    \"white rum\",\n    \"dark rum\",\n    \"tonic water\",\n    \"cola\",\n    \"cranberry juice\",\n    \"simple syrup\",\n    \"soda water\",\n    \"mint leaves\",\n    \"daiquiri bitters\",\n    \"amaretto\",\n    \"cherry brandy\",\n    \"whole milk\",\n    \"single cream\",\n    \"spiced rum\",\n    \"blue curaçao\",\n    \"lime juice\",\n    \"apple juice\",\n    \"lemon-lime soda\",\n    \"dry vermouth\",\n    \"blanco tequila\",\n    \"lemon juice\",\n    \"bianco vermouth\",\n    \"margarita bitters\"\n  ]\n}\n```\n\n## \u003cfont color=\"green\"\u003eGET\u003c/font\u003e /search\n```\nhttp://127.0.0.1:8080/search\n```\nReturns recipes in the API.\n#### Query Params\n##### `ingredients` | string | Optional | Defaults to 'all'\nThe ingredient which is included in all the recipes returned by the API. By default has value `'all'` which does not filter by ingredients.\n\n##### `maxIngredients` | integer | Optional | Defaults to 15\nThe maximum number of ingredients in each of the recipes returned by the API. Must be within the range 2 to 15 inclusive and be greater than or equal to `minIngredients`. By default has value 15 which does not filter by maximum number of ingredients. Returns 400 with an error if out of range.\n\n##### `minIngredients` | integer | Optional | Defaults to 2\nThe minimum number of ingredients in each of the recipes returned by the API. Must be within the range 2 to 15 inclusive and be less than or equal to `maxIngredients`. By default has value 2 which does not filter by minimum number of ingredients. Returns 400 with an error if out of range.\n\n##### `searchOrder` | string | Optional | Defaults to 'oldest'\nThe order in which the results are sorted. By default has a value of `'oldest'`. The values sort the results in the following ways:\n* `'oldest'` - sort recipes in order they were added to the API\n* `'newest'` - sort recipes in order the were added to the API; newest first\n* `'least'` - sort recipes in ascending order by number of ingredients in the recipe\n* `'most'` - sort recipes in descending order by number of ingredients in the recipe\n\n#### Example Request 1 - Valid search with results\n```cmd\ncurl \"http://127.0.0.1:8080/search?ingredients=tonic%20water\u0026maxIngredients=2\"\n```\n#### Response\n```JSON\n{\n  \"drinks\": [\n    {\n      \"strName\": \"GIN \u0026 TONIC\",\n      \"strInstructions\": \"Pour ingredients into ice-filled glass and serve\",\n      \"strImageName\": \"GIN \u0026 TONIC.png\",\n      \"numberIngredients\": 2,\n      \"strIngredient1\": \"gin\",\n      \"strIngredientAmount1\": \"50ml\",\n      \"strIngredient2\": \"tonic water\",\n      \"strIngredientAmount2\": \"120ml\",\n      \"strIngredient3\": null,\n      \"strIngredientAmount3\": null,\n      \"strIngredient4\": null,\n      \"strIngredientAmount4\": null,\n      \"strIngredient5\": null,\n      \"strIngredientAmount5\": null,\n      \"strIngredient6\": null,\n      \"strIngredientAmount6\": null,\n      \"strIngredient7\": null,\n      \"strIngredientAmount7\": null,\n      \"strIngredient8\": null,\n      \"strIngredientAmount8\": null,\n      \"strIngredient9\": null,\n      \"strIngredientAmount9\": null,\n      \"strIngredient10\": null,\n      \"strIngredientAmount10\": null,\n      \"strIngredient11\": null,\n      \"strIngredientAmount11\": null,\n      \"strIngredient12\": null,\n      \"strIngredientAmount12\": null,\n      \"strIngredient13\": null,\n      \"strIngredientAmount13\": null,\n      \"strIngredient14\": null,\n      \"strIngredientAmount14\": null,\n      \"strIngredient15\": null,\n      \"strIngredientAmount15\": null\n    },\n    {\n      \"strName\": \"Vodka \u0026 Tonic\",\n      \"strInstructions\": \"Pour ingredients into an ice-filled glass. Garnish with a lime wedge and serve\",\n      \"strImageName\": \"VODKA \u0026 TONIC.png\",\n      \"numberIngredients\": 2,\n      \"strIngredient1\": \"vodka\",\n      \"strIngredientAmount1\": \"50ml\",\n      \"strIngredient2\": \"tonic water\",\n      \"strIngredientAmount2\": \"120ml\",\n      \"strIngredient3\": null,\n      \"strIngredientAmount3\": null,\n      \"strIngredient4\": null,\n      \"strIngredientAmount4\": null,\n      \"strIngredient5\": null,\n      \"strIngredientAmount5\": null,\n      \"strIngredient6\": null,\n      \"strIngredientAmount6\": null,\n      \"strIngredient7\": null,\n      \"strIngredientAmount7\": null,\n      \"strIngredient8\": null,\n      \"strIngredientAmount8\": null,\n      \"strIngredient9\": null,\n      \"strIngredientAmount9\": null,\n      \"strIngredient10\": null,\n      \"strIngredientAmount10\": null,\n      \"strIngredient11\": null,\n      \"strIngredientAmount11\": null,\n      \"strIngredient12\": null,\n      \"strIngredientAmount12\": null,\n      \"strIngredient13\": null,\n      \"strIngredientAmount13\": null,\n      \"strIngredient14\": null,\n      \"strIngredientAmount14\": null,\n      \"strIngredient15\": null,\n      \"strIngredientAmount15\": null\n    }\n  ]\n}\n```\n\n#### Example Request 2 - Valid search without results\n```cmd\ncurl \"http://127.0.0.1:8080/search?ingredients=cola\u0026maxIngredients=2\"\n```\n#### Response\n```JSON\n{\n    \"drinks\": null\n}\n```\n\n#### Example Request 3 - Invalid search\n```cmd\ncurl \"http://127.0.0.1:8080/search?ingredients=tonic%20water\u0026maxIngredients=1\"\n```\n#### Response\n```JSON\n{\n  \"error\": \"Query param minIngredients out of range (1)\"\n}\n```\n\n## \u003cfont color=\"orange\"\u003ePOST\u003c/font\u003e /submit\n```\nhttp://127.0.0.1:8080/submit\n```\nAdds a recipe to the API.\n#### Request Body\n##### `strName` | string | Required\nThe name of the cocktail.\n##### `strInstructions` | string | Required\nThe instructions for making the cocktail.\n##### `strIngredient1` | string | Required\nThe name of the first ingredient.\n##### `strIngredientAmount1` | string | Required\nThe amount of the first ingredient.\n##### `strIngredient2` | string | Required\nThe name of the second ingredient.\n##### `strIngredientAmount2` | string | Required\nThe amount of the second ingredient.\n##### `strIngredient3` - `strIngredient15` | string | Optional | Defaults to null\nThe name of the third to fifteenth ingredients.\n##### `strIngredientAmount3` - `strIngredientAmount15` | string | Optional | Defaults to null\nThe amount of the third to fifteenth ingredients.\n##### `fileDrinkImg` | file | Optional | Defaults to placeholder image\nAn image of the cocktail. If none is uploaded, a placeholder image is used.\n#### Returns\nHTTP code depending of if request is successful (200) or not (400).\n\n#### Example Request 1 - Post with valid inputs\n```cmd\ncurl http://127.0.0.1:8080/submit -H \"Content-Type: application/json\" -d \"{\\\"strName\\\": \\\"screwdriver\\\",\\\"strInstructions\\\": \\\"Put ingredients in an ice-filled glass and stir with a screwdriver. Garnish with an orange slice.\\\",\\\"strIngredient1\\\": \\\"vodka\\\",\\\"strIngredientAmount1\\\": \\\"60ml\\\",\\\"strIngredient2\\\": \\\"orange juice\\\",\\\"strIngredientAmount2\\\": \\\"90ml\\\"}\"\n```\n#### Response 1 - Drink is new\n```JSON\n{\n  \"message\": \"Recipe successfully uploaded\"\n}\n```\n#### Response 2 - Drink is not new\n```JSON\n{\n  \"error\": \"Name SCREWDRIVER is not unique\"\n}\n```\n\n#### Example Request 2 - Post with extra parameters\n```cmd\ncurl http://127.0.0.1:8080/submit -H \"Content-Type: application/json\" -d \"{\\\"extraParam\\\": \\\"extraInput\\\"}\"\n```\n#### Response\n```JSON\n{\n  \"error\": \"Extra params passed (35)\"\n}\n```\n\n#### Example Request 3 - Post with missing required inputs\n```cmd\ncurl http://127.0.0.1:8080/submit -H \"Content-Type: application/json\" -d \"{\\\"strName\\\": \\\"screwdriver\\\",\\\"strIngredient1\\\": \\\"vodka\\\",\\\"strIngredientAmount1\\\": \\\"60ml\\\",\\\"strIngredient2\\\": \\\"orange juice\\\",\\\"strIngredientAmount2\\\": \\\"90ml\\\"}\"\n```\n#### Response\n```JSON\n{\n  \"error\": \"Missing required inputs\"\n}\n```\n\n#### Example Request 4 - Incomplete ingredient-amount pairs\n```cmd\ncurl http://127.0.0.1:8080/submit -H \"Content-Type: application/json\" -d \"{\\\"strName\\\": \\\"screwdriver\\\",\\\"strInstructions\\\": \\\"Put ingredients in an ice-filled glass and stir with a screwdriver. Garnish with an orange slice.\\\",\\\"strIngredient1\\\": \\\"vodka\\\",\\\"strIngredientAmount1\\\": \\\"60ml\\\",\\\"strIngredient2\\\": \\\"orange juice\\\",\\\"strIngredientAmount2\\\": \\\"90ml\\\",\\\"strIngredient3\\\": \\\"triple sec\\\"}\"\n```\n#### Response\n```JSON\n{\n  \"error\": \"Ingredient-amount pair no. 3 incomplete\"\n}\n```\n\n## \u003cfont color=\"red\"\u003eDELETE\u003c/font\u003e /delete/:recipe\n```\nhttp://127.0.0.1:8080/delete/\n```\nDeletes a recipe from the API.\n#### Query Params\n##### `recipe` | string | Required\nThe name of the recipe to be deleted from the API. Not case sensitive.\n#### Example Request 1 - Request with drink\n```cmd\ncurl \"http://127.0.0.1:8080/delete/artlantic\"\n```\n#### Response 1 - Drink exists\n```JSON\n{\n  \"message\": \"Recipe successfully deleted\"\n}\n```\n#### Response 2 - Drink does not exist\n```JSON\n{\n  \"error\": \"Recipe ATLANTIC not found\"\n}\n```\n#### Example Request 2 - Request with no drink\n```cmd\ncurl \"http://127.0.0.1:8080/delete/\"\n```\n#### Response\n```JSON\n{\n  \"error\": \"Missing required input\"\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frorypoulter%2Fprog-black-web-project","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frorypoulter%2Fprog-black-web-project","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frorypoulter%2Fprog-black-web-project/lists"}