{"id":48856225,"url":"https://github.com/joejo-joestar/joestar-middleware","last_synced_at":"2026-04-15T12:44:09.907Z","repository":{"id":317857074,"uuid":"1069007151","full_name":"joejo-joestar/joestar-middleware","owner":"joejo-joestar","description":"🔌 simple middleware for my portfolio website","archived":false,"fork":false,"pushed_at":"2026-04-13T23:34:46.000Z","size":330,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-15T12:44:08.501Z","etag":null,"topics":["express-middleware","github-api","middleware","now-playing","portfolio-website","spotify-api","unsplash-api","vercel-serverless"],"latest_commit_sha":null,"homepage":"https://api.joestar.is-a.dev","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/joejo-joestar.png","metadata":{"files":{"readme":"README.md","changelog":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-03T08:57:15.000Z","updated_at":"2026-03-29T20:27:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"d6d45977-ebf2-4ef3-97a9-7328051c11a9","html_url":"https://github.com/joejo-joestar/joestar-middleware","commit_stats":null,"previous_names":["joejo-joestar/joestar-middleware"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/joejo-joestar/joestar-middleware","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joejo-joestar%2Fjoestar-middleware","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joejo-joestar%2Fjoestar-middleware/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joejo-joestar%2Fjoestar-middleware/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joejo-joestar%2Fjoestar-middleware/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joejo-joestar","download_url":"https://codeload.github.com/joejo-joestar/joestar-middleware/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joejo-joestar%2Fjoestar-middleware/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31842193,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T11:29:19.690Z","status":"ssl_error","status_checked_at":"2026-04-15T11:29:19.171Z","response_time":63,"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":["express-middleware","github-api","middleware","now-playing","portfolio-website","spotify-api","unsplash-api","vercel-serverless"],"created_at":"2026-04-15T12:44:09.383Z","updated_at":"2026-04-15T12:44:09.895Z","avatar_url":"https://github.com/joejo-joestar.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e🔌 joestar middleware\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"public/pixlinkcar.png\" alt=\"carlink\" title=\"carlink\" width=\"128\" \u003e\n\u003c/p\u003e\n\nA middleware server for [my portfolio website](https://github.com/joejo-joestar/joestar), providing Spotify currently playing track, GitHub activity, and Unsplash photo collections.\nThis project provides a simple Express server with three main API endpoints, each handled in separate route files:\n\n---\n\n## Dependencies\n\n| Package                                                     | Description                                                                                                                      |\n| ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |\n| [express](https://expressjs.com)                            | A minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. |\n| [serve-favicon](https://github.com/expressjs/serve-favicon) | A middleware for serving a favicon.                                                                                              |\n| [http-errors](https://github.com/jshttp/http-errors)        | Create HTTP errors for Express, Koa, Connect, etc.                                                                               |\n| [axios](https://axios-http.com/docs/intro)                  | Promise based HTTP client for the browser and node.js                                                                            |\n| [dotenv](https://github.com/motdotla/dotenv)                | Loads environment variables from a `.env` file into `process.env`                                                                |\n| [cors](https://github.com/expressjs/cors)                   | Node.js CORS middleware                                                                                                          |\n\n---\n\n## Project Structure\n\nBelow is a compact tree of the most important files and folders with a short note about their purpose.\n\n```plaintext\njoestar-middleware/\n├── README.md     # Project documentation\n├── package.json  # npm scripts, dependencies\n├── app.js        # Express entry point\n├── public/         # Static assets served as-is\n│   ├── 404.html    # Oneko cat animation\n│   └── index.html  # Logo image\n├── bin/\n│   └── www  # Server start script\n└── routes/          # Page routes (React Router)\n    ├── github.js    # fetch GitHub repositories for the project owner\n    ├── index.js     # root route, health check\n    ├── spotify.js   # exchange a Spotify refresh token and fetch the \"now playing\" item\n    └── unsplash.js  # fetch Unsplash collections and photos\n```\n\n---\n\n## Endpoints\n\n| Endpoint                           | Request Type | Description                                                                                                                                                                               |\n| ---------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `/unsplash/collections`            | `GET`        | Fetches Unsplash collections for the username `UNSPLASH_USERNAME` in the `.env` file (refer to the [example `.env` file](./.env.example)).                                                |\n| `/unsplash/collections/:id/photos` | `GET`        | Fetches photos from a specified Unsplash collection (`:id` will be replaced with required `collectionId`).                                                                                |\n| `/github/repos`                    | `GET`        | Fetches public repos for the the username `GITHUB_USERNAME` in the `.env` file (refer to the [example `.env` file](./.env.example)), and archived repos, sorted by most recently updated. |\n| `/github/:owner/:repo/readme`      | `GET`        | Fetches the `README.md` for specified GitHub Repo from an owner (`:repo` and `:owner` will be replaced with required values (*case insensitive*)).                                        |\n| `/spotify/now-playing`             | `GET`        | returns simplified now-playing info.                                                                                                                                                      |\n\n---\n\n## Routes\n\n\u003e [!NOTE]\n\u003e All Routes read from environment variables for API keys and tokens. See each section below for details\n\n### Unsplash Route ([`unsplash.ts`](./routes/unsplash.ts))\n\nFetch collections and photos from the Unsplash API for the gallery pages.\n\n#### Unsplash Envs\n\n- `UNSPLASH_CLIENT_ID`: required for the requests in the current implementation.\n- `UNSPLASH_USERNAME`: required for the `user` parameter for the requests\n\n---\n\n### GitHub Route ([`github.ts`](./routes/github.ts))\n\nFetch repositories for the `joejo-joestar` account (used to populate the Projects list).\n\n#### GitHub Envs\n\n- `GITHUB_ACCESS_TOKEN`: required for requests in current implementation\n- `GITHUB_USERNAME`: required for the `user` parameter for the requests\n\n\u003e [!NOTE]\n\u003e The helper sends `Authorization: token ${githubToken}` if `GITHUB_ACCESS_TOKEN` is provided.\n\n---\n\n### Spotify Route ([`spotify.ts`](./routes/spotify.ts))\n\nObtain an access token via a stored refresh token, and fetch the currently-playing item for the authenticated Spotify account.\n\n#### Spotify Envs\n\n- `SPOTIFY_CLIENT_ID`: The `Client ID` from the app created in [Spotify for Developers](https://developer.spotify.com/dashboard/create)\n- `SPOTIFY_CLIENT_SECRET`: The `Client Secret` from the app created in [Spotify for Developers](https://developer.spotify.com/dashboard/create)\n- `SPOTIFY_REFRESH_TOKEN`: The refresh token gotten after following the steps provided in the [Spotify Setup](#spotify-setup) section\n\n\u003e [!NOTE]\n\u003e We use an [Upstash Redis database](https://upstash.com/docs/redis/overall/getstarted) to store (and update) the `SPOTIFY_REFRESH_TOKEN` and a few other variables (more details will be explained in the [Spotify Setup](#spotify-setup) section)\n\u003e\n\u003e These `middleware_*` Variables are also used in the [`utils/get_refresh_token.js`](./utils/get_refresh_token.js) script\n\n- `middleware_KV_REST_API_URL`: The Upstash Redis Database URL\n- `middleware_KV_REST_API_TOKEN`: The Upstash Redis Database API Token\n\n#### Spotify Setup\n\n[This article](https://medium.com/@alagappan.dev/create-a-now-playing-widget-using-the-spotify-web-api-in-react-a6cb564ed923) helped setting up the API calls and tokens for the now playing card. The steps to connect to your spotify account is very convoluted compared to the other endpoints. This is because Spotify is a bitchass crybaby.\n\n- First, head over to [Spotify for Developers](https://developer.spotify.com), create a new app, and fill in the details\n- Take Note of the `Client ID` and the `Client Secret`\n\n  ![App Dashboard Secrets](./assets/spotifyDevDash.png)\n\n- Next, add the local host IP (`http://127.0.0.1:3001/callback`) (Spotify has blacklisted `http://localhost:5173/` from being used as a redirect URI in the [latest update](https://developer.spotify.com/documentation/web-api/concepts/redirect_uri))\n\n  ```plaintext\n  http://127.0.0.1:3001/callback\n  ```\n\n  ![Redirect URIs](./assets/spotifyDevRedirects.png)\n\nNow, we setup an Upstash Redis Database to store the Refresh token, the fresh access token and its ttl.\n\n\u003e [!NOTE]\n\u003e The following steps assume you are using Vercel to deploy this service\n\n- In your deployed project's page, head over to the stores tab\n\n  ![Vercel Dashboard](./assets/VercelDashboard.png)\n\n- Then `Create a Database` and select the `Upstash for Redis` option\n\n  ![Storage Options](./assets/StorageOptions.png)\n\n  \u003e [!NOTE]\n  \u003e You will be asked to create a free account!\n\n- Follow the steps in the following pages and select the free tier (unless you are willing to pay!) and create a database\n- When prompted to enter a custom prefix, put in `middleware` (this repo uses the `middleware` prefix, you can use whatever you want!)\n\n  ![custom prefix dialogue](./assets/CustomPrefixDialogue.png)\n\n- In the console page, you will find the environment variables for the Upstash Redis Database. Save these in your `.env` file for local development and the setup\n\n  ![upstash redis console](./assets/UpstashRedisConsole.png)\n\n\u003e [!Tip]\n\u003e Follow the [Local Development](#local-development) steps before continuing to simplify the whole process!\n\nOnce this prereq is complete, simply run the [utility script](./utils/get_refresh_token.js) and follow the steps to generate a spotify refresh token and store it in the Redis Database!\n\n```bash\nnpm i\nnode utils/get_refresh_token.js\n```\n\n---\n\n## Local Development\n\n1. Clone the repository\n\n```bash\ngit clone https://github.com/joejo-joestar/joestar-middleware\ncd joestar-middleware\n```\n\n2. Run to install dependencies\n\n```bash\nnpm i\n```\n\n3. Create a `.env` file in the root directory with the required environment variables (refer to the [example `.env` file](./.env.example))\n4. Start the server with\n\n```bash\nnpm start\n```\n\n5. Access the endpoints at `http://localhost:3000/\u003cendpoint\u003e`\n\n\u003e [!TIP]\n\u003e You can use an API client to test the endpoints\n\u003e\n\u003e Try out [Yaak Client](https://github.com/mountain-loop/yaak) or [Hoppscotch Web App](https://hoppscotch.io)\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoejo-joestar%2Fjoestar-middleware","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoejo-joestar%2Fjoestar-middleware","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoejo-joestar%2Fjoestar-middleware/lists"}