Skip to content

Commit a4f7122

Browse files
authored
Merge pull request #3 from framer/example/http-server
Introducing JSON server example
2 parents a09cc64 + a74cc12 commit a4f7122

6 files changed

Lines changed: 190 additions & 12 deletions

File tree

examples/csv-importer/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"typecheck": "tsc --noEmit"
88
},
99
"dependencies": {
10-
"framer-api": "^0.0.1-alpha.6",
10+
"framer-api": "^0.0.1-beta.0",
1111
"papaparse": "^5.5.3",
1212
"typescript": "^5.9.3"
1313
},

examples/json-api/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# JSON API
2+
3+
A simple HTTP/JSON server that exposes Framer collections via REST endpoints using [Hono](https://hono.dev).
4+
5+
## Usage
6+
7+
```bash
8+
EXAMPLE_PROJECT_URL="https://framer.com/projects/..." npm run dev
9+
```
10+
11+
The server runs on port 3000 by default.
12+
13+
## Endpoints
14+
15+
### List Collections
16+
17+
```
18+
GET /collections
19+
```
20+
21+
Returns all collections in the project.
22+
23+
### List Items
24+
25+
```
26+
GET /collections/:collectionId
27+
```
28+
29+
Returns all items in a collection by ID.
30+
31+
### Get Item
32+
33+
```
34+
GET /collections/:collectionId/:itemId
35+
```
36+
37+
Returns a single item with its field data.
38+

examples/json-api/package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "json-api",
3+
"version": "0.0.1",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"dev": "node --watch src/index.ts",
8+
"typecheck": "tsc --noEmit"
9+
},
10+
"dependencies": {
11+
"@hono/node-server": "^1.14.1",
12+
"framer-api": "^0.0.1-beta.0",
13+
"hono": "^4.7.10",
14+
"typescript": "^5.9.3"
15+
},
16+
"devDependencies": {
17+
"@types/node": "^22.10.2"
18+
}
19+
}

examples/json-api/src/index.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import assert from "node:assert";
2+
import { serve } from "@hono/node-server";
3+
import { connect, type Framer } from "framer-api";
4+
import { Hono } from "hono";
5+
6+
const projectUrl = process.env["EXAMPLE_PROJECT_URL"];
7+
assert(projectUrl, "EXAMPLE_PROJECT_URL environment variable is required");
8+
9+
interface Variables {
10+
framer: Framer;
11+
}
12+
13+
const app = new Hono<{ Variables: Variables }>();
14+
15+
// Middleware to connect to Framer and set the framer client in the context.
16+
// Will not share the instance between requests
17+
app.use(async (c, next) => {
18+
// The `using` keyword is used to ensure that the Framer client is closed after the block is executed.
19+
// This will automatically end the connection when the request is complete
20+
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/using
21+
using framer = await connect(projectUrl);
22+
c.set("framer", framer);
23+
await next();
24+
});
25+
26+
app.get("/collections", async (c) => {
27+
const allCollections = await c.var.framer.getCollections();
28+
29+
const collections = allCollections.map((col) => ({
30+
id: col.id,
31+
name: col.name,
32+
}));
33+
34+
return c.json({ collections });
35+
});
36+
37+
app.get("/collections/:collectionId", async (c) => {
38+
const collectionId = c.req.param("collectionId");
39+
const allCollections = await c.var.framer.getCollections();
40+
const collection = allCollections.find((col) => col.id === collectionId);
41+
42+
if (!collection) {
43+
return c.json({ error: "Collection not found" }, 404);
44+
}
45+
46+
const allItems = await collection.getItems();
47+
48+
const items = allItems.map((item) => ({
49+
id: item.id,
50+
slug: item.slug,
51+
}));
52+
53+
return c.json({ items });
54+
});
55+
56+
app.get("/collections/:collectionId/:itemId", async (c) => {
57+
const collectionId = c.req.param("collectionId");
58+
const itemId = c.req.param("itemId");
59+
const allCollections = await c.var.framer.getCollections();
60+
const collection = allCollections.find((col) => col.id === collectionId);
61+
62+
if (!collection) {
63+
return c.json({ error: "Collection not found" }, 404);
64+
}
65+
66+
const allItems = await collection.getItems();
67+
68+
const item = allItems.find((i) => i.id === itemId);
69+
70+
if (!item) {
71+
return c.json({ error: "Item not found" }, 404);
72+
}
73+
74+
return c.json(item);
75+
});
76+
77+
serve(app, (info) => {
78+
console.log(`Server running at http://localhost:${info.port}`);
79+
});

examples/json-api/tsconfig.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"extends": "../../tsconfig.base.json",
3+
"include": ["**/*.ts"]
4+
}

package-lock.json

Lines changed: 49 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)