Back to APIs list

Github API examples & templates

Use these vals as a playground to view and fork Github API examples and templates on Val Town. Run any example below or find templates that can be used as a pre-built solution.
ikbear avatar
Bio
@ikbear
HTTP (deprecated)
Forked from stevekrouse/linkInBioTemplate
pomdtr avatar
love_letter
@pomdtr
HTTP (deprecated)
<3 Val Town Val Town is my new favourite thing. Never heard of it ? Well, according to it's homepage, Val Town is a social website to write and deploy TypeScript. It's often introduced as zappier for developers , or twitter for code . The idea is simple: you write down a javascript snippet (named vals) in your browser, and it's instantly executed on a server. You can use it to: execute a function on a cron schedule host a small websites (this article hosted on Val Town ) send yourself emails ... But there is more to Val Town than this. If you take a look at the trending vals , you will quickly notice a pattern: most of the vals are about Val Town itself. People are using Val Town to extend Val Town, and it's fascinating to see what they come up with. I've built a few of these extensions myself, and this article is about one of them. Fixing the Val Town Search Val.town is built around the http import feature of Deno. Each val is a standalone module, that you can import in other vals. It works both for your own vals, and for the vals of other users. All of this is great, but there is one big issue: the search feature is terrible . It only works for exact text matches, and there is no way to set any filters based on username , creation_date , or anything else. This makes it really hard to find a val you are looking for, even if you are the one who wrote it. In any other platform, I would have just given up and moved on. But Val Town is different. I was confident that I could address this issue in userspace, without having to wait for the platform to implement it. Val Town allows you to run a val on a cron schedule, so I wrote a val that would fetch all the vals from the API, and store them as a sqlite table (did I mention that every user get it's own sqlite database ?). const createQuery = `CREATE TABLE IF NOT EXISTS vals ( ... );`; // run every hour export default function(interval: Interval) { // create the val table await options.sqlite.execute(createQuery); let url = "https://api.val.town/v1/search/vals?query=%20&limit=100"; // fetch all vals, and store them in the sqlite table while (true) { const resp = await fetch(url); if (!resp.ok) { throw new Error(await resp.text()); } const res = await resp.json(); const rows = res.data.map(valToRow); await insertRows(rows, options); if (!res.links.next) { break; } url = res.links.next; } } Once the val had finished running, I had a table with all the vals from the platform. I could now run queries on this table to find the vals I was looking for. import { sqlite } from "https://esm.town/v/std/sqlite" const res = await sqlite.execute(`SELECT * FROM vals WHERE author = 'pomdtr' && code LIKE '%search%'`); Of course I could have stopped there, but I wanted to go further. I wanted to share this table with other users, so they could run their own queries on it. Isolating the Vals Table There was still a challenge to overcome: the table was part of my account database, and I didn't want to give everyone access to it (there are some sensitive tables in there). One way to solve this issue would be to publish a stripped-down api that only allows a few predefined queries. But that would be boring, and I wanted to give users the full power of SQL. So I decided to isolate the val table in a separate account. There is a neat trick to achieve this on val.town: each val get's it own email address, and email sent to vals can be forwarded to your own email address. import { email as sendEmail } from "https://esm.town/v/std/email?v=11"; // triggered each time an email is sent to pomdtr.sqlite_email@valtown.email export default async function(email: Email) { // forward the email to my own email address await sendEmail({ subject: email.subject, html: email.html, text: email.text, }); } Since val.town account can be created with a val.email address, you can create an infinite number of accounts (and thus sqlite databases) using this trick. So say hello to the sqlite account , which is a separate account that only contains the vals table. After creating the account, I just needed to fork the cron val from my main account to get a copy of the vals table in the sqlite account. Publishing the Table The val.town stdlib provides a neat rpc function that provides a simple way to expose a function as an API. So I decided to write a simple val that would run a query on the table, and return the result. import { rpc } from "https://esm.town/v/std/rpc?v=5"; import { InStatement, sqlite } from "https://esm.town/v/std/sqlite?v=4"; // rpc create an server, exposed on the val http endpoint export default rpc(async (statement: InStatement) => { try { // run the query, then return the result as json return await sqlite.execute(statement); } catch (e) { throw new Response(e.message, { status: 500, }); } }); Everyone can now run queries on the table thanks a publically accessible endpoint (you even have write access to it, but I trust you to not mess with it). You can test it locally using curl and jq : echo "SELECT * FROM vals WHERE lower(name) LIKE '%feed%' and lower(name) like '%email%' LIMIT 100" | jq -R '{args: [.]} ' | xargs -0 -I {} curl -X POST "https://sqlite-execute.web.val.run" -H "Content-Type: application/json" -d {} | jq Of course I don't expect the average val.town user to use shell commands to run queries, so I also built an helper val to interact with the API, allowing users to run queries from their own vals. // only the import changed from the previous example import { db } from "https://esm.town/v/sqlite/db"; // this query will run on the `sqlite` account const res = await db.execute(`SELECT * FROM vals WHERE author = 'pomdtr' && code LIKE '%search%'`); I've seen some really cool vals built on top of this API. Someone even wrote down a guide to help users interact with it from the command-line! I hope that someone will build an search UI to interact with it at some point, but in the meantime, you can use a community-contributed sqlite web interface to run queries on top of the vals table. Val.town as a code-taking app As I've tried to show, having both a runtime, an editor and an API on the same platform is quite a magic formula. It's probably why val.town resonates so much with me. Using CodeSandbox, Stackblitz, Repl.it, Gitpod, Github Codespaces or Gitpod feels pretty much the same, everything still revolves around the same concept of a project/repository. They feel uninspired somehow, trying to replicate the desktop IDE experience in the browser, instead of embracing the new possibilities that the web platform offers. Val.town breaks this mold. I see it as a code-taking app, a place where I can just dump my ideas without worrying about the usual frictions of writing and deploying code.
std avatar
blob
@std
Script
Blob Storage - Docs β†— Val Town comes with blob storage built-in. It allows for storing any data, like text, JSON, or images. You can access it via std/blob . Blob storage is scoped globally to your account. If you set a blob in one val, you can retrieve it by the same key in another val. It's backed by Cloudflare R2. You may find this admin viewer helpful for viewing and editing your blobs. Get JSON import { blob } from "https://esm.town/v/std/blob"; let blobDemo = await blob.getJSON("myKey"); console.log(blobDemo); // returns `undefined` if not found Set JSON import { blob } from "https://esm.town/v/std/blob"; await blob.setJSON("myKey", { hello: "world" }); List keys import { blob } from "https://esm.town/v/std/blob"; let allKeys = await blob.list(); console.log(allKeys); const appKeys = await blob.list("app_"); console.log(appKeys); // all keys that begin with `app_` Delete by key import { blob } from "https://esm.town/v/std/blob"; await blob.delete("myKey"); Examples Counter RSS Notifications (saving the last run time) Picture: Save & Read Error Handling blob.get can throw ValTownBlobNotFoundError Any method can throw ValTownBlobError for unexpected errors. Utilities Our Blob SDK also includes some utility functions to make working with blobs easier. Copy import { blob } from "https://esm.town/v/std/blob"; await blob.copy("myKey", "myKeyCopy"); Move import { blob } from "https://esm.town/v/std/blob"; await blob.move("myKey", "myKeyNew"); Lower-level API We provide access to the lower-level getter and setters, which are useful if you are storing non-JSON or binary data, need to stream in your response or request data, or do anything else lower-level. async get(key: string) : Retrieves a blob for a given key. async set(key: string, value: string | BodyInit) : Sets the blob value for a given key. See BodyInit . Limitations Blob-stored data counts towards your total Val Town storage – 10mb on the free plan and 1gb on pro. Check our pricing page to learn more. Keys for blobs can be up to 512 characters long. πŸ“ Edit docs
tmcw avatar
jadeOpossum
@tmcw
HTTP (deprecated)
Forked from stevekrouse/dateme
grubdragon avatar
linkInBioTemplate
@grubdragon
HTTP (deprecated)
Forked from stevekrouse/linkInBioTemplate
stevekrouse avatar
Debugging_Guide
@stevekrouse
HTTP
Forked from willthereader/Debugging_Guide
vinspee avatar
createRelease
@vinspee
Script
An interactive, runnable TypeScript val by vinspee
jdan avatar
myspace
@jdan
HTTP (deprecated)
Create your own Myspace profile, deployed to Val town. https://jdan-myspace.web.val.run Click "..." and select Fork to create your own. From there you can: Customize your own profile Or post on my wall by appending to messages and sending me a pull request
std avatar
openai
@std
Script
OpenAI - Docs β†— Use OpenAI's chat completion API with std/openai . This integration enables access to OpenAI's language models without needing to acquire API keys. For free Val Town users, all calls are sent to gpt-4o-mini . Usage import { OpenAI } from "https://esm.town/v/std/openai"; const openai = new OpenAI(); const completion = await openai.chat.completions.create({ messages: [ { role: "user", content: "Say hello in a creative way" }, ], model: "gpt-4", max_tokens: 30, }); console.log(completion.choices[0].message.content); Limits While our wrapper simplifies the integration of OpenAI, there are a few limitations to keep in mind: Usage Quota : We limit each user to 10 requests per minute. Features : Chat completions is the only endpoint available. If these limits are too low, let us know! You can also get around the limitation by using your own keys: Create your own API key on OpenAI's website Create an environment variable named OPENAI_API_KEY Use the OpenAI client from npm:openai : import { OpenAI } from "npm:openai"; const openai = new OpenAI(); πŸ“ Edit docs
vogelino avatar
TanStackBlogToRSS
@vogelino
HTTP (deprecated)
Forked from curtcox/markdown_download
mark05e avatar
niceSnippetPostmanCodegen
@mark05e
HTTP (deprecated)
Forked from tmcw/jsonBodyParsing
curtcox avatar
markdown_download
@curtcox
HTTP (deprecated)
Forked from taras/markdown_download
vawogbemi avatar
dateme
@vawogbemi
HTTP (deprecated)
Forked from stevekrouse/dateme
ghsaboias avatar
linkInBioTemplate
@ghsaboias
HTTP (deprecated)
Forked from stevekrouse/linkInBioTemplate
std avatar
fetch
@std
Script
Proxied fetch - Docs β†— The Javascript Fetch API is directly available within a Val. However sometimes fetch calls are blocked by the receiving server for using particular IP addresses. Additionally, network blips or unreliable web services may lead to failures if not handled properly. The Val Town standard library contains an alternative version, std/fetch , that wraps the JavaScript Fetch API to provide additional functionality. The fetch function from std/fetch reroutes requests using a proxy vendor so that requests obtain different IP addresses. It also automatically retries failed requests several times. Note that using std/fetch will be significantly slower than directly calling the Javascript Fetch API due to extra network hops. Usage After importing std/fetch , the fetch method is used with the same signature as the Javascript Fetch API. import { fetch } from "https://esm.town/v/std/fetch"; let result = await fetch("https://api64.ipify.org?format=json"); let json = await result.json(); console.log(json.ip); If you run the above code multiple times, you'll see that it returns different IP addresses, because std/fetch uses proxies so that each request is made from a different IP address. πŸ“ Edit docs
stevekrouse avatar
pollVulkanRSSFeedBug
@stevekrouse
Script
An interactive, runnable TypeScript val by stevekrouse
…
17
…
Next