{"id":41933471,"url":"https://github.com/melalj/gsheet-api","last_synced_at":"2026-01-25T18:04:20.912Z","repository":{"id":40721225,"uuid":"258546419","full_name":"melalj/gsheet-api","owner":"melalj","description":"Google Spreadsheet REST API Simplified (full CRUD)","archived":false,"fork":false,"pushed_at":"2026-01-20T15:11:38.000Z","size":192,"stargazers_count":22,"open_issues_count":0,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-21T00:11:38.486Z","etag":null,"topics":["google-sheets","google-sheets-api","microservice","rest-api"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/melalj.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}},"created_at":"2020-04-24T15:10:12.000Z","updated_at":"2026-01-20T15:08:25.000Z","dependencies_parsed_at":"2024-02-26T11:26:46.221Z","dependency_job_id":"33826cc2-eeae-4c59-93ae-8ba17aff5a75","html_url":"https://github.com/melalj/gsheet-api","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/melalj/gsheet-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/melalj%2Fgsheet-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/melalj%2Fgsheet-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/melalj%2Fgsheet-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/melalj%2Fgsheet-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/melalj","download_url":"https://codeload.github.com/melalj/gsheet-api/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/melalj%2Fgsheet-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28756432,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-25T16:32:25.380Z","status":"ssl_error","status_checked_at":"2026-01-25T16:32:09.189Z","response_time":113,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["google-sheets","google-sheets-api","microservice","rest-api"],"created_at":"2026-01-25T18:04:20.244Z","updated_at":"2026-01-25T18:04:20.906Z","avatar_url":"https://github.com/melalj.png","language":"TypeScript","readme":"# gsheet-api\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![npm version](https://img.shields.io/badge/version-1.2.0-blue.svg)](https://github.com/melalj/gsheet-api)\n[![Node.js](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org/)\n[![Docker](https://img.shields.io/badge/docker-available-blue.svg)](https://hub.docker.com/r/melalj/gsheet-api)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)\n\n\u003e A lightweight REST API microservice that turns Google Sheets into a backend database with full CRUD operations.\n\nUse Google Spreadsheets as a simple database for your applications. Perfect for prototypes, small projects, internal tools, and MVPs where you need a quick backend without setting up a full database.\n\n[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/melalj/gsheet-api)\n\n[![dockeri.co](https://dockeri.co/image/melalj/gsheet-api)](https://hub.docker.com/r/melalj/gsheet-api)\n\n---\n\n## Table of Contents\n\n- [Features](#features)\n- [Prerequisites](#prerequisites)\n- [Installation](#installation)\n  - [Docker (Recommended)](#docker-recommended)\n  - [Heroku](#heroku)\n  - [Local Development](#local-development)\n- [Configuration](#configuration)\n  - [Google Cloud Setup](#google-cloud-setup)\n  - [Environment Variables](#environment-variables)\n- [API Reference](#api-reference)\n  - [List Spreadsheets](#list-spreadsheets)\n  - [List Sheets](#list-sheets)\n  - [Query Data](#query-data)\n  - [Get Single Row](#get-single-row)\n  - [Insert Rows](#insert-rows)\n  - [Update Rows](#update-rows)\n  - [Delete Rows](#delete-rows)\n  - [Health Check](#health-check)\n- [Security](#security)\n- [Rate Limits \u0026 Quotas](#rate-limits--quotas)\n- [Examples](#examples)\n- [Contributing](#contributing)\n- [License](#license)\n\n---\n\n## Features\n\n- **Full CRUD Operations** - Create, Read, Update, and Delete data in Google Sheets via REST API\n- **Pagination Support** - Built-in pagination for large datasets\n- **Dynamic Columns** - Automatically adds new columns when inserting data with new fields\n- **Smart Type Detection** - Automatically converts values to appropriate types (boolean, integer, float)\n- **Multiple Deployment Options** - Deploy via Docker, Heroku, or run locally\n- **API Key Protection** - Secure your endpoints with API key authentication\n- **Health Checks** - Built-in health check endpoints for monitoring\n- **Lightweight** - Minimal dependencies, fast startup time\n\n---\n\n## Prerequisites\n\nBefore you begin, ensure you have the following:\n\n- **Node.js** \u003e= 18.0.0 (for local development)\n- **Docker** (for containerized deployment)\n- **Google Cloud Platform Account** with:\n  - Google Sheets API enabled\n  - Google Drive API enabled\n  - Service Account with JSON credentials\n\n---\n\n## Installation\n\n### Docker (Recommended)\n\nThe fastest way to get started is using Docker:\n\n```bash\n# Pull and run the container\ndocker run -p 8080:80 -e GOOGLE_CREDENTIALS=$GOOGLE_CREDENTIALS melalj/gsheet-api\n\n# With API key protection\ndocker run -p 8080:80 \\\n  -e GOOGLE_CREDENTIALS=$GOOGLE_CREDENTIALS \\\n  -e PRIVATE_API_KEY=your-secret-key \\\n  melalj/gsheet-api\n```\n\n### Heroku\n\nDeploy instantly with one click:\n\n[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/melalj/gsheet-api)\n\nSet the `GOOGLE_CREDENTIALS` config var in your Heroku app settings.\n\n### Local Development\n\n```bash\n# Clone the repository\ngit clone https://github.com/melalj/gsheet-api.git\ncd gsheet-api\n\n# Install dependencies\nnpm install\n\n# Create .env file with your credentials (see Configuration section)\ncp .env.example .env\n\n# Start the server\nnpm start\n```\n\nThe API will be available at `http://localhost:80/` (customize with `PORT` environment variable).\n\n---\n\n## Configuration\n\n### Google Cloud Setup\n\n1. **Create a Service Account**\n   - Go to the [Service Accounts page](https://console.cloud.google.com/iam-admin/serviceaccounts) in Google Cloud Console\n   - Select your project (or create a new one)\n   - Click **Create Service Account**\n   - Enter a name and description\n   - Grant the role **Editor** (or appropriate permissions)\n   - Click **Done**\n\n2. **Generate JSON Key**\n   - Click on the created service account\n   - Go to the **Keys** tab\n   - Click **Add Key** \u003e **Create new key**\n   - Select **JSON** format\n   - Download and save as `credentials.json`\n\n3. **Enable Required APIs**\n   - [Enable Google Drive API](https://console.developers.google.com/apis/api/drive.googleapis.com/overview)\n   - [Enable Google Sheets API](https://console.developers.google.com/apis/api/sheets.googleapis.com/overview)\n\n4. **Generate Base64 Credentials**\n   ```bash\n   # On Linux/macOS\n   export GOOGLE_CREDENTIALS=$(base64 -w 0 credentials.json)\n\n   # On macOS (alternative)\n   export GOOGLE_CREDENTIALS=$(base64 credentials.json)\n\n   # On Windows (PowerShell)\n   $GOOGLE_CREDENTIALS = [Convert]::ToBase64String([IO.File]::ReadAllBytes(\"credentials.json\"))\n   ```\n\n5. **Share Your Spreadsheet**\n   - Open your Google Spreadsheet\n   - Click **Share**\n   - Add the service account email (found in `credentials.json` as `client_email`)\n   - Grant **Editor** access\n\n### Environment Variables\n\n| Variable | Required | Default | Description |\n|----------|----------|---------|-------------|\n| `GOOGLE_CREDENTIALS` | Yes | - | Base64-encoded Google service account JSON credentials |\n| `PORT` | No | `80` | Port number for the server |\n| `HOST` | No | `0.0.0.0` | Host address to bind to |\n| `PRIVATE_API_KEY` | No | - | API key for `X-Private-Api-Key` header authentication |\n| `PRIVATE_API_KEY_QUERY` | No | - | API key for `?key=` query string authentication |\n| `NODE_ENV` | No | - | Set to `production` for production mode |\n\n#### Example `.env` file\n\n```env\nGOOGLE_CREDENTIALS=eyJ0eXBlIjoic2VydmljZV9hY2NvdW50Ii...\nPORT=3000\nPRIVATE_API_KEY=your-secret-api-key\nNODE_ENV=production\n```\n\n---\n\n## API Reference\n\n### List Spreadsheets\n\nReturns all spreadsheets accessible by the service account.\n\n```http\nGET /\n```\n\n#### Response\n\n```json\n[\n  {\n    \"id\": \"1MNXlNRwbUo4-qbTCdBZGW3Q8sq7pUDov-2ElTFOA0wo\",\n    \"name\": \"My Spreadsheet\",\n    \"modifiedTime\": \"2024-01-15T10:30:00.000Z\"\n  }\n]\n```\n\n---\n\n### List Sheets\n\nReturns all sheets within a spreadsheet.\n\n```http\nGET /:spreadsheetId\n```\n\n#### Parameters\n\n| Name | Type | Description |\n|------|------|-------------|\n| `spreadsheetId` | string | The ID of the spreadsheet (from URL) |\n\n#### Response\n\n```json\n[\n  {\n    \"title\": \"Sheet1\",\n    \"sheetId\": 0,\n    \"rowCount\": 1000,\n    \"columnCount\": 26\n  },\n  {\n    \"title\": \"Sheet2\",\n    \"sheetId\": 123456789,\n    \"rowCount\": 500,\n    \"columnCount\": 10\n  }\n]\n```\n\n---\n\n### Query Data\n\nRetrieves data from a specific sheet with pagination support.\n\n```http\nGET /:spreadsheetId/:sheetName\n```\n\n#### Parameters\n\n| Name | Type | Description |\n|------|------|-------------|\n| `spreadsheetId` | string | The ID of the spreadsheet |\n| `sheetName` | string | The name of the sheet |\n\n#### Query Parameters\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `perPage` | integer | `1000` | Number of rows per page |\n| `offset` | integer | `2` | Starting row number (row 1 is headers) |\n| `maxColumns` | integer | `109` | Maximum number of columns to read |\n| `returnColumn` | string | - | Return only a specific column |\n\n#### Response\n\n```json\n{\n  \"columns\": {\n    \"name\": \"Sheet1!A\",\n    \"email\": \"Sheet1!B\",\n    \"age\": \"Sheet1!C\"\n  },\n  \"pagination\": {\n    \"haveNext\": true,\n    \"totalItems\": 2500,\n    \"range\": \"Sheet1!A2:DD1001\"\n  },\n  \"data\": [\n    {\n      \"name\": \"John Doe\",\n      \"email\": \"john@example.com\",\n      \"age\": 30\n    },\n    {\n      \"name\": \"Jane Smith\",\n      \"email\": \"jane@example.com\",\n      \"age\": 25\n    }\n  ]\n}\n```\n\n---\n\n### Get Single Row\n\nRetrieves a specific row by row number.\n\n```http\nGET /:spreadsheetId/:sheetName/:rowNumber\n```\n\n#### Parameters\n\n| Name | Type | Description |\n|------|------|-------------|\n| `spreadsheetId` | string | The ID of the spreadsheet |\n| `sheetName` | string | The name of the sheet |\n| `rowNumber` | integer | The row number to retrieve |\n\n#### Response\n\n```json\n{\n  \"rowNumber\": 3,\n  \"name\": \"Jane Smith\",\n  \"email\": \"jane@example.com\",\n  \"age\": 25\n}\n```\n\n---\n\n### Insert Rows\n\nAppends new rows to a sheet. Automatically creates new columns if fields don't exist.\n\n```http\nPOST /:spreadsheetId/:sheetName\n```\n\n#### Parameters\n\n| Name | Type | Description |\n|------|------|-------------|\n| `spreadsheetId` | string | The ID of the spreadsheet |\n| `sheetName` | string | The name of the sheet |\n\n#### Query Parameters\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `valueInputOption` | string | `USER_ENTERED` | How input is interpreted: `RAW` or `USER_ENTERED` |\n\n#### Request Body\n\n```json\n[\n  { \"name\": \"Alice\", \"email\": \"alice@example.com\", \"age\": 28 },\n  { \"name\": \"Bob\", \"email\": \"bob@example.com\", \"age\": 32 }\n]\n```\n\n#### Response\n\n```json\n{\n  \"insertedRows\": 2\n}\n```\n\n---\n\n### Update Rows\n\nUpdates specific rows in a sheet. Automatically creates new columns if fields don't exist.\n\n```http\nPUT /:spreadsheetId/:sheetName\n```\n\n#### Parameters\n\n| Name | Type | Description |\n|------|------|-------------|\n| `spreadsheetId` | string | The ID of the spreadsheet |\n| `sheetName` | string | The name of the sheet |\n\n#### Query Parameters\n\n| Name | Type | Default | Description |\n|------|------|---------|-------------|\n| `valueInputOption` | string | `USER_ENTERED` | How input is interpreted: `RAW` or `USER_ENTERED` |\n\n#### Request Body\n\nObject where keys are row numbers and values are the fields to update:\n\n```json\n{\n  \"3\": { \"email\": \"newemail@example.com\" },\n  \"5\": { \"name\": \"Updated Name\", \"age\": 35 }\n}\n```\n\n#### Response\n\n```json\n[\n  {\n    \"spreadsheetId\": \"1MNXlNRwbUo4-qbTCdBZGW3Q8sq7pUDov-2ElTFOA0wo\",\n    \"updatedRange\": \"Sheet1!B3\",\n    \"updatedRows\": 1,\n    \"updatedColumns\": 1,\n    \"updatedCells\": 1\n  },\n  {\n    \"spreadsheetId\": \"1MNXlNRwbUo4-qbTCdBZGW3Q8sq7pUDov-2ElTFOA0wo\",\n    \"updatedRange\": \"Sheet1!A5:C5\",\n    \"updatedRows\": 1,\n    \"updatedColumns\": 2,\n    \"updatedCells\": 2\n  }\n]\n```\n\n---\n\n### Delete Rows\n\nDeletes specific rows from a sheet.\n\n```http\nDELETE /:spreadsheetId/:sheetName\n```\n\n#### Parameters\n\n| Name | Type | Description |\n|------|------|-------------|\n| `spreadsheetId` | string | The ID of the spreadsheet |\n| `sheetName` | string | The name of the sheet |\n\n#### Request Body\n\nArray of row numbers to delete:\n\n```json\n[3, 5, 7]\n```\n\n#### Response\n\n```json\n{\n  \"deletedRows\": 3\n}\n```\n\n---\n\n### Health Check\n\nCheck if the API is running.\n\n```http\nGET /health\nGET /~health\n```\n\n#### Response\n\n```json\n{\n  \"status\": \"ok\"\n}\n```\n\n---\n\n## Security\n\n### API Key Authentication\n\nProtect your endpoints using one of the following methods:\n\n#### Header-based Authentication\n\nSet the `PRIVATE_API_KEY` environment variable and include the key in requests:\n\n```bash\ncurl -H \"X-Private-Api-Key: your-secret-key\" http://localhost:8080/\n```\n\n#### Query String Authentication\n\nSet the `PRIVATE_API_KEY_QUERY` environment variable and include the key in the URL:\n\n```bash\ncurl \"http://localhost:8080/?key=your-secret-key\"\n```\n\n### Best Practices\n\n1. **Always use HTTPS** in production\n2. **Use strong, random API keys** (at least 32 characters)\n3. **Limit service account permissions** to only necessary spreadsheets\n4. **Regularly rotate credentials** and API keys\n5. **Monitor API usage** for suspicious activity\n\n---\n\n## Rate Limits \u0026 Quotas\n\nThis API is subject to [Google Sheets API quotas](https://developers.google.com/sheets/api/limits):\n\n| Limit | Value |\n|-------|-------|\n| Requests per project | 500 per 100 seconds |\n| Requests per user | 100 per 100 seconds |\n| Daily usage limit | None |\n\n**Note:** Read and write operations have separate quotas.\n\n### Recommendations\n\n- Implement caching for frequently accessed data\n- Use batch operations when possible\n- Consider rate limiting on your end for high-traffic applications\n- Monitor your Google Cloud Console for quota usage\n\n---\n\n## Examples\n\n### JavaScript (fetch)\n\n```javascript\n// List all spreadsheets\nconst response = await fetch('http://localhost:8080/', {\n  headers: {\n    'X-Private-Api-Key': 'your-api-key'\n  }\n});\nconst spreadsheets = await response.json();\n\n// Get data from a sheet\nconst data = await fetch(\n  'http://localhost:8080/SPREADSHEET_ID/Sheet1?perPage=100'\n).then(r =\u003e r.json());\n\n// Insert new rows\nawait fetch('http://localhost:8080/SPREADSHEET_ID/Sheet1', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application/json',\n    'X-Private-Api-Key': 'your-api-key'\n  },\n  body: JSON.stringify([\n    { name: 'New User', email: 'user@example.com' }\n  ])\n});\n```\n\n### cURL\n\n```bash\n# List spreadsheets\ncurl -H \"X-Private-Api-Key: your-key\" http://localhost:8080/\n\n# Get data with pagination\ncurl \"http://localhost:8080/SPREADSHEET_ID/Sheet1?perPage=50\u0026offset=2\"\n\n# Insert data\ncurl -X POST http://localhost:8080/SPREADSHEET_ID/Sheet1 \\\n  -H \"Content-Type: application/json\" \\\n  -d '[{\"name\": \"Test\", \"email\": \"test@example.com\"}]'\n\n# Update data\ncurl -X PUT http://localhost:8080/SPREADSHEET_ID/Sheet1 \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"3\": {\"name\": \"Updated Name\"}}'\n\n# Delete rows\ncurl -X DELETE http://localhost:8080/SPREADSHEET_ID/Sheet1 \\\n  -H \"Content-Type: application/json\" \\\n  -d '[3, 4, 5]'\n```\n\n### Python\n\n```python\nimport requests\n\nBASE_URL = 'http://localhost:8080'\nHEADERS = {'X-Private-Api-Key': 'your-api-key'}\n\n# Get all spreadsheets\nspreadsheets = requests.get(BASE_URL, headers=HEADERS).json()\n\n# Get data from sheet\ndata = requests.get(\n    f'{BASE_URL}/SPREADSHEET_ID/Sheet1',\n    params={'perPage': 100},\n    headers=HEADERS\n).json()\n\n# Insert rows\nrequests.post(\n    f'{BASE_URL}/SPREADSHEET_ID/Sheet1',\n    json=[{'name': 'Alice', 'email': 'alice@example.com'}],\n    headers=HEADERS\n)\n```\n\n---\n\n## Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n### Quick Start\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Make your changes\n4. Run linting (`npm run lint`)\n5. Commit your changes (`git commit -m 'Add amazing feature'`)\n6. Push to the branch (`git push origin feature/amazing-feature`)\n7. Open a Pull Request\n\nPlease read our [Code of Conduct](CODE_OF_CONDUCT.md) before contributing.\n\n---\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n---\n\n## Acknowledgments\n\n- Built with [Express.js](https://expressjs.com/)\n- Powered by [Google Sheets API](https://developers.google.com/sheets/api)\n- Inspired by the need for simple, quick backends\n\n---\n\nMade with love by [melalj](https://github.com/melalj) and [contributors](https://github.com/melalj/gsheet-api/graphs/contributors)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmelalj%2Fgsheet-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmelalj%2Fgsheet-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmelalj%2Fgsheet-api/lists"}