Astro Cookies API: Cookies on HTTP Requests
Tags: webdev, astro, javascript
Published: 2023-02-15 11:18:15

---
title: "Astro Cookies API: Cookies on HTTP Requests"
published: "true"
description: "Astro Cookies API 🍪 how you can set and get cookies, passing data between client and server on your 🚀 Astro SSR site."
tags: "webdev, astro, javascript"
canonical_url: "https://rodneylab.com/astro-cookies-api/"
cover_image: "https://dev-to-uploads.s3.amazonaws.com/uploads/articles/inbk9qst5286ehrtqdm0.png"
---

## 🚀 Astro Cookies API

The Astro cookies API provides a way to pass data between user browser and the server. You can use it on your SSR sites, as an example, to keep track of whether a user is authenticated.  Essentially the API is just a wrapper for JavaScript and browser APIs which let you set cookies on HTTP requests by adding a cookies header.  That said the standard APIs have a little boiler-plate code and the Astro Cookie API will save you some typing!

To see how the API works we will look at an example with the Mux video player.  We will see how you might save the video playback position using cookies.  This could be used to let a logged in user resume a video from the right place even if they switch device.  The main goal here is to show how the API works and you can adapt the code we see to work with HTTP cookies in many use cases.

For some cookie use cases you can manage cookies just on the client side with JavaScript APIs. We focus on using cookies in HTTP requests between client and server.

## 🧱 What are we Building?

We will set up a video with Mux video player in an Astro SSR app. In the video component we will use browser APIs to let us know when the user pauses playback.  We then send the playback position to our API endpoint where we can save it to a database ready for the user&rsquo;s next login.  In the API endpoint we will also set the cookie with the playback position using the Astro Cookie API, of course! Finally, in our Astro client code we will have a check for the playback position cookie and pass any value to the video player component.


![Astro Cookies API: Screen capture shows a video in a browser window. There are play, advance and other controls.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7ucizzonoerdrvqojqh.png)

If that sounds like what you were looking for, then why don&rsquo;t we get started? We won&rsquo;t build the app step-by-step but there is a link further down the page to the full project code on GitHub.  You will <a href="https://dashboard.mux.com/signup?type=video">need a Mux account</a> (and to upload some video) to try out the full code, and you can do this for free.

## 🎥 Mux Video Player Component

We are working in Svelte here. This makes it easier to load the script tag we need for the Mux player and also to access the embedded video element APIs.

```svelte
<script lang="ts">
	export let videoId = import.meta.env.PUBLIC_MUX_PLAYBACK_ID as string;
	export let title = 'Raindrops in Super Slow Motion';
	export let startTime = '0';

	const siteUrl = import.meta.env.PUBLIC_SITE_URL;

	let playerElement: HTMLMediaElement;

	async function handlePause() {
		const currentTime = Math.floor(playerElement.currentTime);
		fetch(`${siteUrl}/api/player?startTime=${currentTime}`, {
			method: 'POST',
		});
	}
</script>

<svelte:head><script src="https://cdn.jsdelivr.net/npm/@mux/mux-player"></script></svelte:head>
<figure>
	<mux-player
		bind:this={playerElement}
		playback-id={videoId}
		stream-type="on-demand"
		{title}
		disable-cookies
		start-time={startTime}
		on:timeupdate={console.log(Math.floor(playerElement.currentTime))}
		on:pause={handlePause}
	/>
	<figcaption>
		{title}. Credit: <a href="https://www.videvo.net/profile/Beachfront">Beachfront</a>
	</figcaption>
</figure>

<style>
	mux-player {
		display: flex;
		max-width: var(--max-width-full);
		aspect-ratio: 16 / 9;
	}
</style>
```

We are using a couple of MediaElement API events here.  `onTimeUpdate` (line `27`) tracks playback, letting us know the video is actually playing.  We just console log the `currentTime` here and include it for reference.  We do use the `onPause` event (line `28`) however.  As you might expect, this causes our `handlePause` function to be invoked when the user taps the pause button.  The current time has millisecond precision, which is probably a little more that we need. We use `Math.floor` to truncate the value.

The other thing to note is using browser APIs, we can set the playback start time and do so in line `26`,  This will be passed in when we create an instance of this component later.

In the `handlePause` function, we use `fetch` to send a `POST` HTTP request to our own endpoint with the currentTime as a URL-encoded string.  Let&rsquo;s look at that endpoint code next.

## ▶️ Astro Cookies API: Player Endpoint

This code listens for for HTTP requests on the `http://example.com/api/player`.

```typescript
import type { APIRoute } from 'astro';

const siteUrl = import.meta.env.PUBLIC_SITE_URL;

export const post: APIRoute = async function post({ cookies, redirect, request }) {
	try {
		const { url: requestUrl } = request;
		const { searchParams } = new URL(requestUrl);
		const startTime = searchParams.get('startTime');
		console.log({ startTime });

		cookies.set('start-time', '31', { path: '/' });

		return new Response('', { status: 200 });
	} catch (error: unknown) {
		console.error(`Error in player api route: ${error as string}`);
		return redirect(`${siteUrl}/`);
	}
};
```

You might notice the code is a little slimmed down compared to what you would expect to find in a production app.  We just console log the `startTime` once we have parsed it from the request here.  You would want to store it to the database against the logged in user in a real-world app.

![Astro Cookies API: Screen capture shows Terminal a console log for start Time of 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z49abcdxrx3vl48ndtm4.png)

The code in line `12` is where we set the cookie.  In a complete app, this would probably go in the login logic, so if the user switched device. We would read the `startTime` from the database and set it on the cookie.

### Astro Cookies API

In endpoints you can access the API using the `cookie` object on the API route (as in line `5`).  The API has a few methods which all do exactly what you would expect them to: `get`, `set` and `has` are probably the ones you will be reaching for most often.   In line `12` above we call `set`. The first argument is the cookie name `start-time` in this case. The second argument is the value for that cookie.  It is a simple string here.  It can be an object instead, though you would want to try to limit yourself to types which can automatically serialised with JSON.stringify. 

The final argument to the `set` call is the options.  This is where you can set `expires` as a date, `httpOnly` (for more secure cookies which JavaScript code running in the browser cannot access).  `sameSite` and `secure` are other values you would consider setting here.  Here we just set `path` which is the web page paths the cookie will apply to.

![Astro Cookies API: Screen capture shows browser dev tool with the storage tab open. We can see a start-time cookie set to 31](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6e1o6bwsa4b1cztxis7i.png)

We just return an empty response and this is enough to set the cookie on the user device.  The final part is to read this data client-side, which we see next.

## 🧑🏽 Astro Cookies API: Reading Cookies Client-side

To access the Astro Cookie API from the client, we can use the `Astro` global.  One thing to note is that the cookie API is only accessible in `.astro` and API endpoint files. Because of that, we read in the cookie value in the `index.astro` client file and pass it as a prop to the Video component.

```html
---
import '~styles/fonts.css';
import '~styles/global.css';
import Video from '~components/Video.svelte';

const startTime = Astro.cookies.get('start-time').value ?? '0';

const title = 'Astro Cookies API';
const description = 'Astro Cookies API: mux video position save example';
---

<head>
	<meta charset="UTF-8" />
	<meta name="viewport" content="width=device-width" />
	<link rel="icon" href="/favicon.ico" sizes="any" />
	<link rel="icon" href="/icon.svg" type="image/svg+xml" />
	<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
	<link rel="manifest" href="/manifest.webmanifest" />
	<title>{title}</title>
	{description ? <meta name="description" content={description} /> : null}
</head>
<main>
	<h1>Astro Cookies API 🍪</h1>
	<Video client:load {startTime} />
</main>
```

We call `Astro.cookies.get('cookie-name').value` here to retrieve the string value we stored in the endpoint.  If we had stored an object, instead of a string, then we would have used:

```javascript
Astro.cookies.get('cookie-name').json()
```

That gets us back an object.  If we pause the video, then refresh the browser, the video skips to `31` . seconds (the value we set on the cookie). Remember in a real-world app we would have pulled an actual `startTime` value from our database and used that value instead of out arbitrary `31` value.

![Astro Cookies API: Screen capture shows video player in browser. The video is ready to play with the current time at 31 seconds.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6njfxbaqs6dq069ys86o.png)

## 🙌🏽 Astro Cookies API: Wrapping Up

In this post, we saw how the Astro Cookies API works and also some browser Media Element APIs.  In particular we saw:

- how to **set cookies in a server endpoint** in Astro,
- how to **read cookies in client code**,
- a way to capture **video current time and a pause action** in Svelte.


You can see the <a href="https://github.com/rodneylab/astro/tree/main/demos/astro-cookies-api">full code for this project in the Rodney Lab GitHub repo</a>. I do hope you have found this post useful! I am keen to hear what you are doing with Astro and ideas for future projects.  Also let me know about any possible improvements to the content above.

## 🙏🏽 Astro Cookies API: Feedback

Have you found the post useful? Would you prefer to see posts on another topic instead? Get in touch with ideas for new posts. Also if you like my writing style, get in touch if I can write some posts for your company site on a consultancy basis. Read on to find ways to get in touch, further below. If you want to support posts similar to this one and can spare a few dollars, euros or pounds, please <a aria-label="Support Rodney Lab via Buy me a Coffee" href="https://rodneylab.com/giving/">consider supporting me through Buy me a Coffee</a>.

Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via <a aria-label="at ask Rodney" href="https://twitter.com/messages/compose?recipient_id=1323579817258831875">@askRodney</a> on Twitter, <a href="https://toot.community/@rodney">@rodney@toot.community</a> on Mastodon and also the <a aria-label="Contact Rodney Lab via Telegram" href="https://matrix.to/#/%23rodney:matrix.org">#rodney</a> Element Matrix room. Also, see <a aria-label="Get in touch with Rodney Lab" href="https://rodneylab.com/contact/">further ways to get in touch with Rodney Lab</a>. I post regularly on <a aria-label="See posts on Astro" href="https://rodneylab.com/tags/astro/">Astro</a> as well as <a aria-label="See posts on svelte kit" href="https://rodneylab.com/tags/seo/">SEO</a>. Also <a aria-label="Subscribe to the Rodney Lab newsletter" href="https://newsletter.rodneylab.com/issue/latest-issue">subscribe to the newsletter to keep up-to-date</a> with our latest projects.