> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pinata.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Astro

> Get started using Pinata with Astro

This guide will walk you through setting up Pinata with Astro

## Create an API Key and get Gateway URL

To create an API key, visit the [Keys Page](https://app.pinata.cloud/developers/keys) and click the "New Key" button in the top right. Once you do that you can select if you want your key to be admin or if you want to scope the privileges of the keys to certain endpoints or limit the number of uses. Make those selections, then give the key a name at the bottom, and click create key.

<Note>
  If you are just getting started we recommend using Admin privileges, then move
  to scope keys as you better understand your needs
</Note>

<img style={{ borderRadius: "0.5rem" }} src="https://docs.mypinata.cloud/ipfs/bafybeignh2yy7bp7qpts5vi46prbjd6lbz23lmtbfcgvpcwc5rjkudrfta" />

Once you have created the keys you will be shown your API Key Info. This will contain your **Api Key**, **API Secret**, and your **JWT**. Click "Copy All" and save them somewhere safe!

<Note>
  The API keys are only shown once, be sure to copy them somewhere safe!
</Note>

After you have your API key, you will want to get your Gateway domain. When you create a Pinata account, you'll automatically have a Gateway created for you! To see it, simply visit the [Gateways Page](https://app.pinata.cloud/gateway) see it listed there.

<img style={{ width: "100%", borderRadius: "0.5rem" }} src="https://docs.mypinata.cloud/ipfs/bafkreiaedels7u6z6f3dwgmp5t25a2o74xt2kqe4kf72tk6orri7hrbfy4" />

The gateway domains are randomly generated and might look something like this:

```
aquamarine-casual-tarantula-177.mypinata.cloud
```

## Setup Astro

To create a new Astro project go ahead and run this command in the terminal:

```bash theme={null}
npm create astro@latest pinata-astro
```

You can select which options you prefer, but for this exmaple we'll use the following:

```
tmpl   How would you like to start your new project?
       Empty

  ts   Do you plan to write TypeScript?
       Yes

 use   How strict should TypeScript be?
       Strict

deps   Install dependencies?
       Yes

 git   Initialize a new git repository?
       Yes
```

After completing the project setup we can go ahead and `cd` into the repo and install `pinata`.

```bash theme={null}
cd pinata-astro && npm i pinata
```

Since we want to keep our API key private we will need to make sure our code is deployed server side, and we can use several different adapter options which you can view [here](https://docs.astro.build/en/guides/server-side-rendering/). We also need a UI framework to handle our upload form, and there are many to choose from [here](https://docs.astro.build/en/guides/framework-components/). We'll use `vercel` and `svelte` for this tutorial, and you can install them like so.

```bash theme={null}
npx astro add vercel svelte
```

This should install the dependencies and alter the `astro.config.mjs` for us.

## Setup Pinata

In the `src` folder make a new folder called `utils`, and inside there make a file called `pinata.ts` with the following contents:

```typescript src/utils/pinata.ts theme={null}
import { PinataSDK } from "pinata";

export const pinata = new PinataSDK({
	pinataJwt: import.meta.env.PINATA_JWT,
	pinataGateway: import.meta.env.GATEWAY_URL,
});
```

This will create and export an instance of the Files SDK using environment variables, and to set those up make a new file at the root of the project called `.env` with the following values:

```
PINATA_JWT= # The Pinata JWT API key we got earlier
GATEWAY_URL= # The Gateway domain we grabbed earlier, formatting just as we copied it from the app
```

## Create Client Side Form

In the `src` folder make another folder called `components`, then inside there make file called `UploadForm.svelte`.

```html src/components/UploadForm.svelte theme={null}
<script lang="ts">
let url: string;
let isUploading: boolean;

async function submit(e: SubmitEvent) {
	isUploading = true;
	e.preventDefault();
	const formData = new FormData(e.currentTarget as HTMLFormElement);
	const request = await fetch("/api/upload", {
		method: "POST",
		body: formData,
	});
	const response = await request.json();
	url = response.data;
	isUploading = false;
}
</script>

<style>
  img {
    max-width: 500px;
  }
  form {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 2rem;
  }
  button {
   background-color: #6E57FF;
   color: white;
   border: none;
   border-radius: 5px;
   padding: 0.75rem 1.5rem;
   font-weight: bold;
  }
</style>

<form on:submit={submit}>
  <input type="file" id="file" name="file" required />
  <button>{isUploading ? "Uploading..." : "Upload"}</button>
  {#if url}
    <img src={url} alt="pinnie" />
  {/if}
</form>
```

This component creates a `<form>` with a file `<input>` as well as a `<button>` to send it. The form will trigger the `submit` function, which takes our form data and makes an API request to our server side code. Once complete the API will send response with a `url` that we can use in the `<img>` tag to display it on the page.

## Server Side API Route

In the `src/pages` folder make a new folder called `api` and inside there make a file called `upload.ts`. Paste the following code inside it:

```typescript theme={null}
import type { APIRoute } from "astro";
import { pinata } from "../../utils/pinata";

export const POST: APIRoute = async ({ request }) => {
	const data = await request.formData();
	const file = data.get("file") as File;
	if (!file) {
		return new Response(
			JSON.stringify({
				message: "Missing file",
			}),
			{ status: 400 },
		);
	}
	const { cid } = await pinata.upload.public.file(file);
	const url = await pinata.gateways.public.convert(cid)
	return new Response(
		JSON.stringify({
			data: url,
		}),
		{ status: 200 },
	);
};
```

This simple API route will parse the incoming `formData` and get the `file` we attached. If there isn't a file attached we'll send a error response. Otherwise we'll upload the file using the SDK method `pinata.upload.public.file` and deconstruct the response to get the `cid`. With that `cid` we can use the `convert` method to create a URL, which we can then send back to the client.

## Add Component to the Page

The last step here is to update the `src/pages/index.astro` file with our new component!

```html src/pages/index.astro theme={null}
---
import UploadForm from "../components/UploadForm.svelte";
---

<html lang="en">
	<head>
		<meta charset="utf-8" />
		<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
		<meta name="viewport" content="width=device-width" />
		<meta name="generator" content={Astro.generator} />
		<title>Astro</title>
	</head>
	<body>
		<h1>Astro + Pinata</h1>
		<UploadForm client:load />
	</body>
</html>
```
