-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from holaplex/espi/upload-files
Upload files to w3.storage using web3up
- Loading branch information
Showing
6 changed files
with
292 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ yarn-error.log* | |
.pnpm-debug.log* | ||
|
||
# local env files | ||
.env | ||
.env*.local | ||
|
||
# vercel | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,29 @@ | ||
# HUB Uploads | ||
# HUB Upload API | ||
|
||
A simple REST wrapper for web3up used as a shared uploads service within HUB. | ||
This is the Upload API for HUB. It allows users to upload files to the server. | ||
|
||
## Getting started | ||
## Setup | ||
|
||
``` | ||
npm i | ||
npm run start | ||
``` | ||
To setup the server, follow these steps: | ||
|
||
1. Install the dependencies by running `npm install` | ||
2. Set the environment variables `WEB3_UP_KEY`, `WEB3_UP_PROOF`, and `WEB3_UP_GATEWAY`. Note that `WEB3_UP_GATEWAY` should be an IPFS compatible gateway for retrieving assets over HTTP. | ||
3. Start the server by running `npm start` | ||
|
||
## Routes | ||
|
||
The available routes are: | ||
|
||
- POST /uploads: Upload a file. This route consumes multipart/form-data and returns the URI and CID of the uploaded file. | ||
|
||
## Swagger Documentation | ||
|
||
The Swagger documentation for the API is available at /documentation. | ||
|
||
## Error Handling | ||
|
||
If there is a validation error in the request, the server will respond with a 400 status code and the validation error. | ||
|
||
## File Upload | ||
|
||
The server uses the `fastify-multipart` plugin to handle file uploads. The server is configured to accept a maximum of 1 file field and 0 non-file fields. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,161 @@ | ||
import Fastify from "fastify"; | ||
import MultiPart from "@fastify/multipart"; | ||
import { Signer } from "@ucanto/principal/ed25519"; | ||
import fastifyMultiPart from "@fastify/multipart"; | ||
import fastifySwagger from "@fastify/swagger"; | ||
import fastifyEnv from "@fastify/env"; | ||
import fastifySwaggerUi from "@fastify/swagger-ui"; | ||
|
||
import { w3 } from "./web3.js"; | ||
import createError from "@fastify/error"; | ||
|
||
const UploadError = createError( | ||
"UPLOAD_ERROR", | ||
"The upload was not successful" | ||
); | ||
|
||
// Initialize Fastify with logging enabled | ||
const fastify = Fastify({ | ||
logger: true, | ||
}); | ||
|
||
fastify.register(MultiPart); | ||
// Register environment variables | ||
await fastify.register(fastifyEnv, { | ||
dotenv: true, | ||
schema: { | ||
type: "object", | ||
required: ["WEB3_UP_PROOF", "WEB3_UP_KEY", "WEB3_UP_GATEWAY"], | ||
properties: { | ||
WEB3_UP_PROOF: { | ||
type: "string", | ||
}, | ||
WEB3_UP_KEY: { | ||
type: "string", | ||
}, | ||
WEB3_UP_GATEWAY: { | ||
type: "string", | ||
}, | ||
PORT: { | ||
type: "number", | ||
default: 3000, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
// Register multipart plugin with limits | ||
await fastify.register(fastifyMultiPart, { | ||
limits: { | ||
fields: 0, // Max number of non-file fields | ||
files: 1, // Max number of file fields | ||
}, | ||
}); | ||
|
||
await fastify.register(fastifySwagger, { | ||
exposeRoute: true, | ||
swagger: { | ||
info: { | ||
title: "HUB Upload API", | ||
description: "Upload API for HUB", | ||
version: "0.1.0", | ||
}, | ||
externalDocs: { | ||
url: "https://docs.holaplex.com", | ||
description: "HUB documentation", | ||
}, | ||
host: "localhost:3000", | ||
schemes: ["http"], | ||
consumes: ["application/json"], | ||
produces: ["application/json"], | ||
tags: [], | ||
securityDefinitions: { | ||
apiKey: { | ||
type: "apiKey", | ||
name: "Authorization", | ||
in: "header", | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
await fastify.register(fastifySwaggerUi, { | ||
routePrefix: "/documentation", | ||
initOAuth: {}, | ||
uiConfig: { | ||
docExpansion: "full", | ||
deepLinking: false, | ||
}, | ||
uiHooks: { | ||
onRequest: function (request, reply, next) { | ||
next(); | ||
}, | ||
preHandler: function (request, reply, next) { | ||
next(); | ||
}, | ||
}, | ||
staticCSP: true, | ||
transformStaticCSP: (header) => header, | ||
}); | ||
|
||
// Initialize uploader with environment variables | ||
const uploader = await w3( | ||
fastify.config.WEB3_UP_KEY, | ||
fastify.config.WEB3_UP_PROOF, | ||
fastify.config.WEB3_UP_GATEWAY | ||
); | ||
|
||
// Health check endpoint | ||
fastify.get("/health", async function handler(request, reply) { | ||
reply.send({ status: "ok" }); | ||
}); | ||
|
||
// Declare a route | ||
fastify.post("/uploads", async function handler(request, reply) { | ||
const parts = req.files(); | ||
// Upload endpoint | ||
fastify.post( | ||
"/uploads", | ||
{ | ||
schema: { | ||
description: "Upload a file", | ||
tags: ["file"], | ||
consumes: ["multipart/form-data"], | ||
response: { | ||
200: { | ||
description: "File uploaded successfully", | ||
type: "object", | ||
properties: { | ||
uri: { type: "string" }, | ||
cid: { type: "string" }, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
async function handler(request, reply) { | ||
if (request.validationError) { | ||
reply.status(400).send(request.validationError); | ||
return; | ||
} | ||
|
||
for await (const part of parts) { | ||
} | ||
try { | ||
// Get file from request and convert to buffer | ||
const data = await request.file(); | ||
const buffer = await data.toBuffer(); | ||
// Upload file and get results | ||
const results = await uploader.uploadFile(buffer); | ||
|
||
reply.send(); | ||
}); | ||
// Send results as response | ||
reply.send(results); | ||
} catch { | ||
// Send upload error as response if any error occurs | ||
reply.send(new UploadError()); | ||
} | ||
} | ||
); | ||
|
||
// Run the server! | ||
// Start the server | ||
try { | ||
await fastify.listen({ port: 3000, host: "0.0.0.0" }); | ||
await fastify.ready(); | ||
fastify.swagger(); | ||
await fastify.listen({ port: fastify.config.PORT, bind: "0.0.0.0" }); | ||
} catch (err) { | ||
// Log error and exit process if server fails to start | ||
fastify.log.error(err); | ||
process.exit(1); | ||
} |
Oops, something went wrong.