The Service API runs at api.solidjs.com and acts as a central datastore for critical SolidJS.com and supporting service operations. The API srevices REPL, SolidHack and has a general authentication system using GitHub OAuth powered by the wonderful folks at Stytch.
Our services runs on Cloudflare Workers. The following code base is meant to be minimal and extendable. This is a high-throughput services so keeping is
- Stytch API
- Supabase JS API & Client
- Cloudflare Workers
- Clone the project locally:
git clone https://github.com/solidjs/solid-service-api
- Change directory into your local copy:
cd solid-service-api
- Install the dependencies:
yarn install
yarn install
: Install the dependenciesyarn dev
: Start the dev server using Miniflareyarn build
: Builds the entire package using vite-plugin-cloudflareyarn format
: Format the whole project with prettieryarn deploy
: Deploys the service via Wrangler
In order to run the API successfully you'll need to setup a local .env file with the necessary configuration details. The following env should be copy and pasted into the root then populated with proper credentials:
STYTCH_PROJECT_ID=
STYTCH_SECRET=
STYTCH_API=
STYTCH_URL=
ENVIRONMENT=
SUPABASE_URL=
SUPABASE_KEY=
Once that's done you should be able to run yarn dev
to initialize the service locally with Miniflare.
The API uses a Bearer token to authenticate secure endpoints. Once you complete the login process and retain a JWT token (see login) all further requests to the API should contained the Authorization
hearer with Bearer [jwt token]
. The JWT is signed with our Stytch secret. The JWT is encoded with a minimal amount of user information.
The API endpoints use standard HTTP status codes for errors and a consistent error response structure:
{
"status_code": "SOME_ERROR",
"status_message": "A descriptive error response."
}
The following is an outline of endpoints that the service provides. Note that you may find a Postman collection set in the root of the directory. This should help with quickly getting setup and making calls
This endpoint is used to trigger the OAuth login process. A redirect querystring value is necessary to ensure the user is sent back to the current location. You should link a user directly to this endpoint which will in turn redirect to Stytch for GitHub authentication, back to the authorize callback endpoint and then finally to the redirect path in the query. The querystring of the last redirect will contain a token value with a JWT for accessing this service.
Retrieves the current users profile and responds with basic information:
{
"id": "MDQ6VsdfklcjExNjgzOTc=",
"display": "foobar",
"avatar": "https://avatars.githubusercontent.com/u/9277648?v=4",
"github_register": "2010-11-02T21:13:42Z"
}
This REPL collection enables endpoints to manage repl listings and powers the Solid Playground. REPL records have a set of basic information: REPL data
, labels
, Solid version
, size in bytes
, creation date
and updated date
.
Note that the following API uses a constant structure for describing a REPL file. It uses the following shape:
{
"name": "main.tsx",
"content": "import { createSignal, onCleanup } from \"solid-js\";\r\nimport { render } from \"solid-js\/web\";\r\n\r\nconst CountingComponent = () => {\r\n\tconst [count, setCount] = createSignal(0);\r\n\tconst interval = setInterval(\r\n\t\t() => setCount(c => c + 1),\r\n\t\t1000\r\n\t);\r\n\tonCleanup(() => clearInterval(interval));\r\n\treturn <div>Count value is {count()}<\/div>;\r\n};\r\n\r\nrender(() => <CountingComponent \/>, document.getElementById(\"app\"));"
}
The REPL endpoint supports authenticated REPL and anonymous creation. Since anonymous REPLs have no user associated this API issues a special token keyed to the REPL record. This token is only issued on record creation and can never be retrieved afterwards. The token is to be supplied during update/patching of the REPL record in the future.
Returns a list of REPLs owned by the current user. The endpoint is paginated and can potentially support filters. The List and List User REPLs endpoints work the same. If the user requests/repl/davedbase it will show only that users public list.
{
"total": 1,
"list": [
{
"id": "77aa5eec-19bd-471c-8b49-bd11a07c6544",
"title": "Counter Example",
"labels": ["examples", "basic"],
"files": [],
"version": "1.0",
"public": true,
"size": 54,
"created_at": "2022-04-13T15:09:54.671307+00:00",
"updated_at": null
}
]
}
Creates a new REPL record for the user. The REPL creation endpoint supports anonymous content as well. When a user token isn't supplied the service will create the record without any user association and return a write_token
property. This may be used in place of the Bearer token in the PATCH
and PUT
endpoints.
Request:
{
"title": "Counter Example",
"version": "1.0",
"public": true,
"labels": ["examples", "basic"],
"files": []
}
Response:
{
"id": "77aa5eec-19bd-471c-8b49-bd11a07c6547"
}
Transfers a REPL from one user to another. Transfers of anonymous REPLs are also by supplying a write_token. The following example shows a request with a token.
Request:
{
"write_token": "...."
}
Response:
{}
Update a new REPL record for the user. This endpoint accepts write_token
in the body in place of the Bearer token if an anonymous REPL is to be edited. This token is issued on REPL creation.
Request:
{
"title": "Counter Example",
"version": "1.0",
"public": true,
"labels": ["examples", "basic"],
"files": []
}
Response:
{
"id": "77aa5eec-19bd-471c-8b49-bd11a07c6547"
}
Retrieves a REPL based on the UUID.
{
"title": "Counter Example",
"user_id": "DDQ6VDKNlcjExNjgzOTc=",
"version": "1.0",
"labels": ["examples", "basic"],
"public": true,
"files": [],
"created_at": "2022-04-15T16:41:24.918092+00:00",
"updated_at": null
}
Delets a REPL based on the UUID. Successful deletions will return a status 200. Note that the service uses soft deletes. They are not retrievable via the API but are marked in the database itself.
Retrieves a full list of Solid ecosystem packages. The type property can currently be packages
or resources
.
[
{
"author": "Maksim Ivanov",
"author_url": "https://www.youtube.com/user/satansdeer1",
"categories": ["educational"],
"description": "Maksim Ivanov walks us through Solid.js and how to use it.",
"keywords": [""],
"link": "https://www.youtube.com/watch?v=wu6HvLoi9VQ",
"published_at": 1628532062000,
"title": "How To Convert React Application To SolidJS",
"type": "video"
}
]
Allows an external user to submit a new Solidex entry for approval. This endpoint is not fully complete and will return only dummy data. It's request body looks like the following, it's return result should be a record UUID.
{
"author": "Maksim Ivanov",
"author_url": "https://www.youtube.com/user/satansdeer1",
"categories": ["educational"],
"description": "Maksim Ivanov walks us through Solid.js and how to use it.",
"keywords": [""],
"link": "https://www.youtube.com/watch?v=wu6HvLoi9VQ",
"published_at": 1628532062000,
"title": "How To Convert React Application To SolidJS",
"type": "video"
}
- Ability to have public/private REPL storage
- Added validation for REPL file format (based on our original .json structure)
- Adjusted get endpoint to return public REPL without auth token
- Added anonymous REPL creation + write_token for patch and update
- Improved error responses for invalid token/user on write update/patch
- Added REPL transfer mechanism
- Add better validation for certain endpoints
- Parse and validate REPLs with more granular detail (refer to Solid REPL output)
- Private/public mode for REPL
- Retrieve public REPLs
- Add endpoint for requesting other user REPLs
- Anonymous REPL creation
- Transfer REPLs between users
- Handle request where application/json isn't sent as body type
- Make REPL searchable
- Add revision history and ability to retrieve
- Add ability to fork a REPL
- Enable user blocking options
- Add ability to save REPL to a gist
- Add ability to create a repository of an example
- Move REPL packaging and zipping to the API
A special thank you to to Christian Hansen ch99q for initially setting up the foundations of this project and sorting out the Stytch integration. A big thank you to M. Bagher Abiat Aslemammad who made vite-plugin-cloudflare which is one of the best utilities we've seen for working with Cloudflare.