{"id":31250551,"url":"https://github.com/romulooliveira94/romin-bites","last_synced_at":"2026-05-09T16:53:41.438Z","repository":{"id":311983986,"uuid":"1045874168","full_name":"RomuloOliveira94/romin-bites","owner":"RomuloOliveira94","description":"RESTful API for restaurant management, menus, and menu items, built with Ruby on Rails 8.0.2 following the JSON:API specification.","archived":false,"fork":false,"pushed_at":"2025-08-28T01:39:09.000Z","size":109,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-28T05:50:42.453Z","etag":null,"topics":["ruby","ruby-on-rails"],"latest_commit_sha":null,"homepage":"https://rominbites.romin.dev.br","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RomuloOliveira94.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2025-08-27T20:58:22.000Z","updated_at":"2025-08-27T21:40:51.000Z","dependencies_parsed_at":"2025-08-28T05:50:47.090Z","dependency_job_id":"9db0aafe-6981-452d-9dec-d0759a3e4b34","html_url":"https://github.com/RomuloOliveira94/romin-bites","commit_stats":null,"previous_names":["romulooliveira94/romin-bites"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/RomuloOliveira94/romin-bites","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RomuloOliveira94%2Fromin-bites","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RomuloOliveira94%2Fromin-bites/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RomuloOliveira94%2Fromin-bites/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RomuloOliveira94%2Fromin-bites/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RomuloOliveira94","download_url":"https://codeload.github.com/RomuloOliveira94/romin-bites/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RomuloOliveira94%2Fromin-bites/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276519117,"owners_count":25656554,"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","status":"online","status_checked_at":"2025-09-23T02:00:09.130Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["ruby","ruby-on-rails"],"created_at":"2025-09-23T05:30:04.412Z","updated_at":"2025-09-23T05:30:05.874Z","avatar_url":"https://github.com/RomuloOliveira94.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Romin Bites API Documentation\n\n## 📋 Overview\n\nRESTful API for restaurant management, menus, and menu items, built with Ruby on Rails 8.0.2 following the JSON:API specification.\n\n## 🚀 Tech Stack\n\n- **Ruby on Rails** 8.0.2\n- **SQLite3** (Database)\n- **JSON:API Serializer** (Response formatting)\n- **Puma** (Web server)\n- **RSpec** (Testing framework)\n- **GitHub Actions** (CI/CD)\n\n## 📦 Installation\n\n### Prerequisites\n\n- Ruby 3.x\n- Bundler\n- SQLite3\n\n### Setup\n\n```bash\n# Clone the repository\ngit clone \u003crepository-url\u003e\ncd romin-bites\n\n# Install dependencies\nbundle install\n\n# Setup database\nrails db:create\nrails db:migrate\nrails db:seed\n\n# Run the server\nrails server\n```\n\n## 📡 API Endpoints\n\n### Base URL\n\n```\nhttps://rominbites.romin.dev.br/api/v1\n```\n\n### Authentication\n\nCurrently, the API does not require authentication (public access).\n\n---\n\n## 🏪 Restaurants\n\n### List all restaurants\n\n```http\nGET /api/v1/restaurants\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/restaurants\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n**Response:**\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"restaurant\",\n      \"attributes\": {\n        \"name\": \"Bella Italia\",\n        \"description\": \"Authentic Italian cuisine\",\n        \"created_at\": \"2025-08-25T10:00:00.000Z\",\n        \"updated_at\": \"2025-08-25T10:00:00.000Z\"\n      },\n      \"relationships\": {\n        \"menus\": {\n          \"data\": []\n        }\n      }\n    }\n  ]\n}\n```\n\n### Get a specific restaurant\n\n```http\nGET /api/v1/restaurants/:id\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/restaurants/1\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n### Include menus with restaurant\n\n```http\nGET /api/v1/restaurants/:id?include=menus\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/restaurants/1?include=menus\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n**Response with includes:**\n\n```json\n{\n  \"data\": {\n    \"id\": \"1\",\n    \"type\": \"restaurant\",\n    \"attributes\": {\n      \"name\": \"Bella Italia\",\n      \"description\": \"Authentic Italian cuisine\",\n      \"created_at\": \"2025-08-25T10:00:00.000Z\",\n      \"updated_at\": \"2025-08-25T10:00:00.000Z\"\n    },\n    \"relationships\": {\n      \"menus\": {\n        \"data\": [\n          {\n            \"id\": \"1\",\n            \"type\": \"menu\"\n          }\n        ]\n      }\n    }\n  },\n  \"included\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"menu\",\n      \"attributes\": {\n        \"name\": \"Lunch Menu\",\n        \"description\": \"Available from 12:00 to 15:00\",\n        \"created_at\": \"2025-08-25T10:00:00.000Z\",\n        \"updated_at\": \"2025-08-25T10:00:00.000Z\"\n      },\n      \"relationships\": {\n        \"menu_items\": {\n          \"data\": []\n        }\n      }\n    }\n  ]\n}\n```\n\n### Include nested menu items\n\n```http\nGET /api/v1/restaurants/:id?include=menus.menu_items\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/restaurants/1?include=menus.menu_items\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n### Import restaurants from file\n\n```http\nPOST /api/v1/restaurants/import\n```\n\n**cURL Example:**\n\n```bash\ncurl -X POST \"https://rominbites.romin.dev.br/api/v1/restaurants/import\" \\\n  -H \"Accept: application/json\" \\\n  -F \"file=@restaurants.json\"\n```\n\n**Response:**\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Import queued for processing\",\n  \"job_id\": \"12345-67890-abcdef\",\n  \"status_url\": \"https://rominbites.romin.dev.br/api/v1/restaurants/import_status?job_id=12345-67890-abcdef\"\n}\n```\n\n### Check import status\n\n```http\nGET /api/v1/restaurants/import_status?job_id=:job_id\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/restaurants/import_status?job_id=12345-67890-abcdef\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n**Response (Processing):**\n\n```json\n{\n  \"success\": false,\n  \"message\": \"Still processing\",\n  \"job_id\": \"12345-67890-abcdef\"\n}\n```\n\n**Response (Completed - Success):**\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Import completed successfully\",\n  \"logs\": {\n    \"restaurants\": {\n      \"success\": [\n        \"Restaurant 'Bella Italia' created with ID: 1\",\n        \"Restaurant 'Pizza Palace' found with ID: 2\"\n      ],\n      \"error\": []\n    },\n    \"menus\": {\n      \"success\": [\n        \"Menu 'Lunch Menu' created for restaurant Bella Italia with ID: 1\",\n        \"Menu 'Dinner Menu' created for restaurant Bella Italia with ID: 2\"\n      ],\n      \"error\": []\n    },\n    \"menu_items\": {\n      \"success\": [\n        \"Menu item 'Margherita Pizza' created with price: 12.99 and ID: 1\",\n        \"Menu item 'Caesar Salad' found with ID: 2\"\n      ],\n      \"error\": []\n    },\n    \"associations\": {\n      \"success\": [\n        \"Association created between 'Margherita Pizza' and 'Lunch Menu'\",\n        \"Association created between 'Caesar Salad' and 'Lunch Menu'\"\n      ],\n      \"error\": []\n    }\n  },\n  \"stats\": {\n    \"restaurants_created\": 1,\n    \"restaurants_found\": 1,\n    \"menus_created\": 2,\n    \"menus_found\": 0,\n    \"menu_items_created\": 1,\n    \"menu_items_found\": 1,\n    \"associations_created\": 2\n  }\n}\n```\n\n**Response (Completed - With Errors):**\n\n```json\n{\n  \"success\": false,\n  \"message\": \"Import completed with errors\",\n  \"logs\": {\n    \"restaurants\": {\n      \"success\": [\n        \"Restaurant 'Bella Italia' created with ID: 1\"\n      ],\n      \"error\": [\n        \"Error creating restaurant 'Invalid Restaurant': Name can't be blank\"\n      ]\n    },\n    \"menus\": {\n      \"success\": [\n        \"Menu 'Lunch Menu' created for restaurant Bella Italia with ID: 1\"\n      ],\n      \"error\": [\n        \"Error in menu 'Invalid Menu' for restaurant Bella Italia: Name can't be blank\"\n      ]\n    },\n    \"menu_items\": {\n      \"success\": [\n        \"Menu item 'Margherita Pizza' created with price: 12.99 and ID: 1\"\n      ],\n      \"error\": [\n        \"Error creating menu item 'Invalid Item': Price must be greater than or equal to 0\"\n      ]\n    },\n    \"associations\": {\n      \"success\": [\n        \"Association created between 'Margherita Pizza' and 'Lunch Menu'\"\n      ],\n      \"error\": []\n    }\n  },\n  \"stats\": {\n    \"restaurants_created\": 1,\n    \"restaurants_found\": 0,\n    \"menus_created\": 1,\n    \"menus_found\": 0,\n    \"menu_items_created\": 1,\n    \"menu_items_found\": 0,\n    \"associations_created\": 1\n  }\n}\n```\n\n**Response (Failed):**\n\n```json\n{\n  \"success\": false,\n  \"message\": \"Import failed: Invalid JSON format\",\n  \"errors\": [\"Invalid JSON format\"],\n  \"logs\": [],\n  \"stats\": {}\n}\n```\n\n---\n\n## 🍽️ Menus\n\n### List all menus\n\n```http\nGET /api/v1/menus\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/menus\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n### List menus for a specific restaurant\n\n```http\nGET /api/v1/restaurants/:restaurant_id/menus\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/restaurants/1/menus\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n**Response:**\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"menu\",\n      \"attributes\": {\n        \"name\": \"Lunch Menu\",\n        \"description\": \"Available from 12:00 to 15:00\",\n        \"created_at\": \"2025-08-25T10:00:00.000Z\",\n        \"updated_at\": \"2025-08-25T10:00:00.000Z\"\n      },\n      \"relationships\": {\n        \"menu_items\": {\n          \"data\": []\n        }\n      }\n    }\n  ]\n}\n```\n\n### Get a specific menu\n\n```http\nGET /api/v1/menus/:id\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/menus/1\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n### Include menu items with menu\n\n```http\nGET /api/v1/menus/:id?include=menu_items\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/menus/1?include=menu_items\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n**Response with includes:**\n\n```json\n{\n  \"data\": {\n    \"id\": \"1\",\n    \"type\": \"menu\",\n    \"attributes\": {\n      \"name\": \"Lunch Menu\",\n      \"description\": \"Available from 12:00 to 15:00\",\n      \"created_at\": \"2025-08-25T10:00:00.000Z\",\n      \"updated_at\": \"2025-08-25T10:00:00.000Z\"\n    },\n    \"relationships\": {\n      \"menu_items\": {\n        \"data\": [\n          {\n            \"id\": \"1\",\n            \"type\": \"menu_item\"\n          }\n        ]\n      }\n    }\n  },\n  \"included\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"menu_item\",\n      \"attributes\": {\n        \"name\": \"Margherita Pizza\",\n        \"description\": \"Fresh tomatoes, mozzarella, basil\",\n        \"price\": \"12.99\",\n        \"created_at\": \"2025-08-25T10:00:00.000Z\",\n        \"updated_at\": \"2025-08-25T10:00:00.000Z\"\n      },\n      \"relationships\": {\n        \"menus\": {\n          \"data\": []\n        }\n      }\n    }\n  ]\n}\n```\n\n---\n\n## 🍕 Menu Items\n\n### List all menu items\n\n```http\nGET /api/v1/menu_items\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/menu_items\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n### List menu items for a specific menu\n\n```http\nGET /api/v1/menus/:menu_id/menu_items\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/menus/1/menu_items\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n**Response:**\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"menu_item\",\n      \"attributes\": {\n        \"name\": \"Margherita Pizza\",\n        \"description\": \"Fresh tomatoes, mozzarella, basil\",\n        \"price\": \"12.99\",\n        \"created_at\": \"2025-08-25T10:00:00.000Z\",\n        \"updated_at\": \"2025-08-25T10:00:00.000Z\"\n      },\n      \"relationships\": {\n        \"menus\": {\n          \"data\": []\n        }\n      }\n    }\n  ]\n}\n```\n\n### Get a specific menu item\n\n```http\nGET /api/v1/menu_items/:id\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/menu_items/1\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n### Include menus with menu item\n\n```http\nGET /api/v1/menu_items/:id?include=menus\n```\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://rominbites.romin.dev.br/api/v1/menu_items/1?include=menus\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\"\n```\n\n**Response with includes:**\n\n```json\n{\n  \"data\": {\n    \"id\": \"1\",\n    \"type\": \"menu_item\",\n    \"attributes\": {\n      \"name\": \"Margherita Pizza\",\n      \"description\": \"Fresh tomatoes, mozzarella, basil\",\n      \"price\": \"12.99\",\n      \"created_at\": \"2025-08-25T10:00:00.000Z\",\n      \"updated_at\": \"2025-08-25T10:00:00.000Z\"\n    },\n    \"relationships\": {\n      \"menus\": {\n        \"data\": [\n          {\n            \"id\": \"1\",\n            \"type\": \"menu\"\n          }\n        ]\n      }\n    }\n  },\n  \"included\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"menu\",\n      \"attributes\": {\n        \"name\": \"Lunch Menu\",\n        \"description\": \"Available from 12:00 to 15:00\",\n        \"created_at\": \"2025-08-25T10:00:00.000Z\",\n        \"updated_at\": \"2025-08-25T10:00:00.000Z\"\n      },\n      \"relationships\": {\n        \"menu_items\": {\n          \"data\": []\n        }\n      }\n    }\n  ]\n}\n```\n\n---\n\n## 📊 Response Format\n\nAll responses follow the JSON:API specification:\n\n### Success Response Structure\n\n```json\n{\n  \"data\": {\n    \"id\": \"1\",\n    \"type\": \"resource_type\",\n    \"attributes\": {\n      // resource attributes\n    },\n    \"relationships\": {\n      // resource relationships\n    }\n  },\n  \"included\": [\n    // related resources when using include parameter\n  ]\n}\n```\n\n### Error Response Structure\n\n```json\n{\n  \"error\": \"Error message\"\n}\n```\n\n## 🔍 Query Parameters\n\n### Include Related Resources\n\nYou can include related resources using the `include` parameter:\n\n- `?include=menus` - Include menus (for restaurants)\n- `?include=menu_items` - Include menu items (for menus)\n- `?include=menus.menu_items` - Include nested relationships (menus with their menu items)\n\n**Examples:**\n\n```bash\n# Get restaurant with its menus\ncurl \"https://rominbites.romin.dev.br/api/v1/restaurants/1?include=menus\"\n\n# Get restaurant with menus and their items\ncurl \"https://rominbites.romin.dev.br/api/v1/restaurants/1?include=menus.menu_items\"\n\n# Get menu with its items\ncurl \"https://rominbites.romin.dev.br/api/v1/menus/1?include=menu_items\"\n\n# Get menu item with its menus\ncurl \"https://rominbites.romin.dev.br/api/v1/menu_items/1?include=menus\"\n```\n\n## 📝 Model Attributes\n\n### Restaurant\n\n- **id** (integer) - Unique identifier\n- **name** (string, required) - Restaurant name\n- **description** (text, optional) - Restaurant description\n- **created_at** (datetime) - Creation timestamp\n- **updated_at** (datetime) - Last update timestamp\n\n### Menu\n\n- **id** (integer) - Unique identifier\n- **name** (string, required) - Menu name\n- **description** (text, optional) - Menu description\n- **restaurant_id** (integer, required) - Reference to restaurant\n- **created_at** (datetime) - Creation timestamp\n- **updated_at** (datetime) - Last update timestamp\n\n### MenuItem\n\n- **id** (integer) - Unique identifier\n- **name** (string, required, unique) - Menu item name\n- **description** (text, optional) - Item description\n- **price** (decimal, required, \u003e= 0) - Item price with 2 decimal places\n- **created_at** (datetime) - Creation timestamp\n- **updated_at** (datetime) - Last update timestamp\n\n## 🔄 Relationships\n\n- **Restaurant** has many **Menus** (one-to-many)\n- **Menu** belongs to **Restaurant** (many-to-one)\n- **Menu** has many **MenuItems** (many-to-many through join table)\n- **MenuItem** has many **Menus** (many-to-many through join table)\n\n## ⚡ HTTP Status Codes\n\n- **200 OK** - Successful GET request\n- **202 Accepted** - Import job queued or still processing\n- **404 Not Found** - Resource not found\n- **422 Unprocessable Content** - Missing required parameters\n- **500 Internal Server Error** - Server error during import\n\n## 🛠️ Development\n\n### Running Tests\n\n```bash\n# Run all tests\nbundle exec rspec\n\n# Run specific test file\nbundle exec rspec spec/requests/api/v1/restaurants_spec.rb\n\n# Run with documentation format\nbundle exec rspec --format documentation\n```\n\n### Code Quality\n\n```bash\n# Security analysis\nbundle exec brakeman\n\n# Code style\nbundle exec rubocop\n\n# N+1 query detection (in development)\n# Bullet gem is configured to detect N+1 queries\n```\n\n## 📄 License\n\nThis project is open source and available under the MIT License.\n\n---\n\n**Note:** This API follows RESTful conventions and JSON:API specification. All timestamps are in ISO 8601 format (UTC).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fromulooliveira94%2Fromin-bites","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fromulooliveira94%2Fromin-bites","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fromulooliveira94%2Fromin-bites/lists"}