{"id":17012246,"url":"https://github.com/ngscheurich/ephemera","last_synced_at":"2026-04-27T12:38:32.361Z","repository":{"id":75375732,"uuid":"121777516","full_name":"ngscheurich/ephemera","owner":"ngscheurich","description":"🍃 Exposes recent web activity via a GraphQL endoint","archived":false,"fork":false,"pushed_at":"2018-04-04T16:29:48.000Z","size":46,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-10T17:19:10.128Z","etag":null,"topics":["elixir","graphql","phoenix","spotify"],"latest_commit_sha":null,"homepage":"https://github.com/ngscheurich/ephemera","language":"Elixir","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/ngscheurich.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}},"created_at":"2018-02-16T17:09:37.000Z","updated_at":"2019-03-29T20:25:30.000Z","dependencies_parsed_at":"2023-06-06T07:45:23.155Z","dependency_job_id":null,"html_url":"https://github.com/ngscheurich/ephemera","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ngscheurich/ephemera","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngscheurich%2Fephemera","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngscheurich%2Fephemera/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngscheurich%2Fephemera/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngscheurich%2Fephemera/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ngscheurich","download_url":"https://codeload.github.com/ngscheurich/ephemera/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngscheurich%2Fephemera/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32337274,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"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":["elixir","graphql","phoenix","spotify"],"created_at":"2024-10-14T06:09:58.927Z","updated_at":"2026-04-27T12:38:32.343Z","avatar_url":"https://github.com/ngscheurich.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🍃 Ephemera\n\nAfter launching my [personal website](https://nick.scheurich.me/), I started to feel the desire,\nas one does, to display my recent web activity in different places on the site. You know the stuff\nI’m talking about: Spotify tracks, Tweets, Instagram posts. As my website is simply the output of a\n[static site generator](http://gohugo.io/), I would clearly need some external resource to handle\nthis for me. Enter: Ephemera.\n\n## Table of contents\n\n* [Ephemera](#-ephemera)\n  * [Table of Contents](#table-of-contents)\n  * [Configuration](#configuration)\n     * [Spotify](#spotify)\n  * [Retrieving data](#retrieving-data)\n  * [Roadmap](#roadmap)\n  * [Development](#development)\n    * [Service adapters](#service-adapters)\n      * [Specification](#specification)\n      * [Example](#example)\n  * [License](#license)\n\n## Configuration\n\n### Spotify\n\nConfigure `Ephemera.Spotify` for the `:ephemera` app with your Spotify client ID, client secret,\nand refresh token. For production, these should probably be kept somewhere safe, e.g., the system\nenvironment:\n\n```elixir\nconfig :ephemera, Ephemera.Spotify,\n  client_id: Map.fetch!(System.get_env(), \"SPOTIFY_CLIENT_ID\"),\n  client_secret: Map.fetch!(System.get_env(), \"SPOTIFY_CLIENT_SECRET\"),\n  refresh_token: Map.fetch!(System.get_env(), \"SPOTIFY_REFRESH_TOKEN\")\n```\n\n## Retrieving data\n\nAn endpoint at the root path of the application exposes data as per the [GraphQL spec](http://facebook.github.io/graphql/October2016/).\nA simple JavaScript example to get some data about recent Spotify tracks could look something like:\n\n```JavaScript\nconst query = `\n  {\n    spotifyTracks {\n      name\n      artist\n    }\n  }\n`;\n\nconst xhr = new XMLHttpRequest();\nxhr.responseType = \"json\";\nxhr.open(\"POST\", \"https://your-ephemera-app.com/\");\nxhr.setRequestHeader(\"Content-Type\", \"application/json\");\nxhr.setRequestHeader(\"Accept\", \"application/json\");\nxhr.onload= () =\u003e console.log(xhr.response.data.spotifyTracks);\nxhr.send(JSON.stringify({ query }));\n```\n\n## Roadmap\n\nThe following are the services I plan to implement initially:\n\n- [x] Spotify\n- [ ] Twitter\n- [ ] Instagram\n\n## Development\n\n### Service adapters\n\nEphemera has a *service adapter* for each service it supports, which is just a fancy way to say a\ncollection of modules that implement an admittedly loosely-defined spec. One day, these service adapters\nmight be extracted into their own Hex packages, but that day is not today.\n\n#### Specification\n\nA service adapter must consist of the following parts:\n\n* A `Client` spec that defines how clients for this adapter should behave\n* An `HTTPClient` that implements the client behaviour to interface with the service’s web API\n* One or more `Worker`s that implement the GenServer behaviour and interact with clients to generate and maintain an internal state\n\nThe idea that is that all state in the application is ephemeral—hence the name—so `Worker` process state is\nnot persisted in any external data store. If a `Worker` dies, its supervisor should just spin up a new one, at\nwhich point the state will be regenerated.\n\n#### Example\n\nThe Spotify adapter, for instance, has the following modules:\n\n- `Client`: Defines Spotify client behaviour\n- `HTTPClient`: A client that interfaces with Spotify’s web API\n- `GrantWorker`: A worker that maintains and refreshes Spotify web API authorization grants\n- `TracksWorker`: A worker that keeps a list of recently-played Spotify tracks\n\nIn addition, the Spotify adapter also includes an `InMemoryClient` that mocks the Spotify web API\nfor testing, and defines `Grant` and `Track` structs.\n\n## License\n\nEphemera is released under the [MIT license](https://github.com/ngscheurich/ephemera/blob/master/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngscheurich%2Fephemera","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fngscheurich%2Fephemera","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngscheurich%2Fephemera/lists"}