Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/csv-importer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"framer-api": "^0.0.1-alpha.6",
"framer-api": "^0.0.1-beta.0",
"papaparse": "^5.5.3",
"typescript": "^5.9.3"
},
Expand Down
38 changes: 38 additions & 0 deletions examples/json-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# JSON API

A simple HTTP/JSON server that exposes Framer collections via REST endpoints using [Hono](https://hono.dev).

## Usage

```bash
EXAMPLE_PROJECT_URL="https://framer.com/projects/..." npm run dev
```

The server runs on port 3000 by default.

## Endpoints

### List Collections

```
GET /collections
```

Returns all collections in the project.

### List Items

```
GET /collections/:collectionId
```

Returns all items in a collection by ID.

### Get Item

```
GET /collections/:collectionId/:itemId
```

Returns a single item with its field data.

19 changes: 19 additions & 0 deletions examples/json-api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "json-api",
"version": "0.0.1",
"private": true,
"type": "module",
"scripts": {
"dev": "node --watch src/index.ts",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Dev script runs TypeScript without TypeScript runtime

The dev script uses node --watch src/index.ts to run a TypeScript file directly, but Node.js cannot execute TypeScript files without either a TypeScript runtime like tsx or experimental flags. The csv-importer example correctly adds tsx to devDependencies for this purpose, but json-api lacks this dependency. Running npm run dev will fail with a syntax error on most Node.js versions.

Fix in Cursor Fix in Web

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works fine with modern node versions. Welcome to the future, LLM.

"typecheck": "tsc --noEmit"
},
"dependencies": {
"@hono/node-server": "^1.14.1",
"framer-api": "^0.0.1-beta.0",
"hono": "^4.7.10",
"typescript": "^5.9.3"
},
"devDependencies": {
"@types/node": "^22.10.2"
}
}
79 changes: 79 additions & 0 deletions examples/json-api/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import assert from "node:assert";
import { serve } from "@hono/node-server";
import { connect, type Framer } from "framer-api";
import { Hono } from "hono";

const projectUrl = process.env["EXAMPLE_PROJECT_URL"];
assert(projectUrl, "EXAMPLE_PROJECT_URL environment variable is required");

interface Variables {
framer: Framer;
}

const app = new Hono<{ Variables: Variables }>();

// Middleware to connect to Framer and set the framer client in the context.
// Will not share the instance between requests
app.use(async (c, next) => {
// The `using` keyword is used to ensure that the Framer client is closed after the block is executed.
// This will automatically end the connection when the request is complete
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/using
using framer = await connect(projectUrl);
c.set("framer", framer);
await next();
});

app.get("/collections", async (c) => {
const allCollections = await c.var.framer.getCollections();

const collections = allCollections.map((col) => ({
id: col.id,
name: col.name,
}));

return c.json({ collections });
});

app.get("/collections/:collectionId", async (c) => {
const collectionId = c.req.param("collectionId");
const allCollections = await c.var.framer.getCollections();
const collection = allCollections.find((col) => col.id === collectionId);

if (!collection) {
return c.json({ error: "Collection not found" }, 404);
}

const allItems = await collection.getItems();

const items = allItems.map((item) => ({
id: item.id,
slug: item.slug,
}));

return c.json({ items });
});

app.get("/collections/:collectionId/:itemId", async (c) => {
const collectionId = c.req.param("collectionId");
const itemId = c.req.param("itemId");
const allCollections = await c.var.framer.getCollections();
const collection = allCollections.find((col) => col.id === collectionId);

if (!collection) {
return c.json({ error: "Collection not found" }, 404);
}

const allItems = await collection.getItems();

const item = allItems.find((i) => i.id === itemId);

if (!item) {
return c.json({ error: "Item not found" }, 404);
}

return c.json(item);
});

serve(app, (info) => {
console.log(`Server running at http://localhost:${info.port}`);
});
4 changes: 4 additions & 0 deletions examples/json-api/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.base.json",
"include": ["**/*.ts"]
}
60 changes: 49 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.