|
| 1 | +# Ruby Device Management API |
| 2 | + |
| 3 | +A Ruby-based HTTP server application for managing IoT devices with PostgreSQL database integration and Prometheus metrics. This is a Ruby equivalent of the Node.js application in the `node-app` folder. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +This application provides a RESTful API for managing device records, including: |
| 8 | +- Device listing and creation |
| 9 | +- PostgreSQL database integration |
| 10 | +- Prometheus metrics for monitoring |
| 11 | +- Health check endpoint |
| 12 | + |
| 13 | +## Features |
| 14 | + |
| 15 | +- **HTTP Server**: Built with Rack and WEBrick |
| 16 | +- **Database**: PostgreSQL integration using the `pg` gem |
| 17 | +- **Metrics**: Prometheus histogram metrics for tracking database operation duration |
| 18 | +- **RESTful API**: Endpoints for device management |
| 19 | +- **Docker Support**: Multi-stage Dockerfile for containerized deployment |
| 20 | + |
| 21 | +## Prerequisites |
| 22 | + |
| 23 | +- Ruby 3.3 or higher |
| 24 | +- PostgreSQL database |
| 25 | +- Bundler gem (usually comes with Ruby) |
| 26 | + |
| 27 | +## Installation |
| 28 | + |
| 29 | +1. Install dependencies: |
| 30 | +```bash |
| 31 | +bundle install |
| 32 | +``` |
| 33 | + |
| 34 | +## Configuration |
| 35 | + |
| 36 | +The application uses a `config.yaml` file for configuration. Create or modify `config.yaml`: |
| 37 | + |
| 38 | +```yaml |
| 39 | +--- |
| 40 | +appPort: 8080 |
| 41 | +db: |
| 42 | + user: node |
| 43 | + password: devops123 |
| 44 | + host: postgresql.antonputra.pvt |
| 45 | + database: mydb |
| 46 | + maxConnections: 75 |
| 47 | +``` |
| 48 | +
|
| 49 | +**Note**: Update the database connection details to match your PostgreSQL setup. |
| 50 | +
|
| 51 | +## Running the Application |
| 52 | +
|
| 53 | +### Local Development |
| 54 | +
|
| 55 | +1. Ensure PostgreSQL is running and accessible |
| 56 | +2. Make sure the database and `node_device` table exist (see migration notes below) |
| 57 | +3. Start the server: |
| 58 | +```bash |
| 59 | +ruby app.rb |
| 60 | +``` |
| 61 | + |
| 62 | +The server will start on `http://0.0.0.0:8080` (or the port specified in `config.yaml`). |
| 63 | + |
| 64 | +### Using Docker |
| 65 | + |
| 66 | +1. Build the Docker image: |
| 67 | +```bash |
| 68 | +docker build -t ruby-app-node-equivalent . |
| 69 | +``` |
| 70 | + |
| 71 | +2. Run the container: |
| 72 | +```bash |
| 73 | +docker run -p 8080:8080 ruby-app-node-equivalent |
| 74 | +``` |
| 75 | + |
| 76 | +## API Endpoints |
| 77 | + |
| 78 | +### GET /api/devices |
| 79 | + |
| 80 | +Returns a list of sample devices. |
| 81 | + |
| 82 | +**Response:** |
| 83 | +```json |
| 84 | +[ |
| 85 | + { |
| 86 | + "id": 1, |
| 87 | + "uuid": "9add349c-c35c-4d32-ab0f-53da1ba40a2a", |
| 88 | + "mac": "5F-33-CC-1F-43-82", |
| 89 | + "firmware": "2.1.6", |
| 90 | + "created_at": "2024-05-28T15:21:51.137Z", |
| 91 | + "updated_at": "2024-05-28T15:21:51.137Z" |
| 92 | + }, |
| 93 | + ... |
| 94 | +] |
| 95 | +``` |
| 96 | + |
| 97 | +### POST /api/devices |
| 98 | + |
| 99 | +Creates a new device in the database. |
| 100 | + |
| 101 | +**Request Body:** |
| 102 | +```json |
| 103 | +{ |
| 104 | + "mac": "AA-BB-CC-DD-EE-FF", |
| 105 | + "firmware": "1.0.0" |
| 106 | +} |
| 107 | +``` |
| 108 | + |
| 109 | +**Response (201 Created):** |
| 110 | +```json |
| 111 | +{ |
| 112 | + "id": 4, |
| 113 | + "uuid": "generated-uuid", |
| 114 | + "mac": "AA-BB-CC-DD-EE-FF", |
| 115 | + "firmware": "1.0.0", |
| 116 | + "created_at": "2024-11-08T12:34:56.789Z", |
| 117 | + "updated_at": "2024-11-08T12:34:56.789Z" |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +**Error Response (400 Bad Request):** |
| 122 | +```json |
| 123 | +{ |
| 124 | + "message": "Error message" |
| 125 | +} |
| 126 | +``` |
| 127 | + |
| 128 | +### GET /metrics |
| 129 | + |
| 130 | +Returns Prometheus metrics in text format. This endpoint exposes the `myapp_request_duration_seconds` histogram metric that tracks database operation durations. |
| 131 | + |
| 132 | +### GET /healthz |
| 133 | + |
| 134 | +Health check endpoint. Returns `OK` if the server is running. |
| 135 | + |
| 136 | +**Response:** |
| 137 | +``` |
| 138 | +OK |
| 139 | +``` |
| 140 | +
|
| 141 | +## Database Schema |
| 142 | +
|
| 143 | +The application expects a PostgreSQL table named `node_device` with the following structure: |
| 144 | +
|
| 145 | +```sql |
| 146 | +CREATE TABLE node_device ( |
| 147 | + id SERIAL PRIMARY KEY, |
| 148 | + uuid VARCHAR(255) NOT NULL, |
| 149 | + mac VARCHAR(255) NOT NULL, |
| 150 | + firmware VARCHAR(255) NOT NULL, |
| 151 | + created_at TIMESTAMP NOT NULL, |
| 152 | + updated_at TIMESTAMP NOT NULL |
| 153 | +); |
| 154 | +``` |
| 155 | + |
| 156 | +## Project Structure |
| 157 | + |
| 158 | +``` |
| 159 | +ruby-app-node-equivalent/ |
| 160 | +├── app.rb # Main HTTP server application |
| 161 | +├── config.rb # Configuration loader |
| 162 | +├── config.yaml # Configuration file |
| 163 | +├── db.rb # PostgreSQL database connection |
| 164 | +├── devices.rb # Device database operations |
| 165 | +├── metrics.rb # Prometheus metrics setup |
| 166 | +├── Gemfile # Ruby dependencies |
| 167 | +├── Dockerfile # Docker build configuration |
| 168 | +├── .dockerignore # Docker ignore patterns |
| 169 | +└── README.md # This file |
| 170 | +``` |
| 171 | + |
| 172 | +## Dependencies |
| 173 | + |
| 174 | +- **pg**: PostgreSQL database adapter |
| 175 | +- **prometheus-client**: Prometheus metrics client library |
| 176 | +- **rack**: Web server interface |
| 177 | +- **yaml**: YAML configuration parsing (built-in) |
| 178 | + |
| 179 | +## Metrics |
| 180 | + |
| 181 | +The application tracks database operation duration using a Prometheus histogram metric: |
| 182 | + |
| 183 | +- **Metric Name**: `myapp_request_duration_seconds` |
| 184 | +- **Type**: Histogram |
| 185 | +- **Labels**: `op` (operation type, e.g., "db") |
| 186 | +- **Buckets**: Custom buckets optimized for low-latency operations (0.00001 to 17.5 seconds) |
| 187 | + |
| 188 | +## Error Handling |
| 189 | + |
| 190 | +- Database errors are caught and returned as 400 Bad Request with an error message |
| 191 | +- Invalid JSON in POST requests will result in a 400 error |
| 192 | +- All errors are logged to stdout |
| 193 | + |
| 194 | +## Notes |
| 195 | + |
| 196 | +- The server uses a 60-second keep-alive timeout |
| 197 | +- UUIDs are automatically generated using Ruby's `SecureRandom.uuid` |
| 198 | +- Timestamps are generated in ISO 8601 format with millisecond precision |
| 199 | +- The application uses a single PostgreSQL connection (connection pooling can be added if needed) |
| 200 | + |
0 commit comments