adding cookies to api route response [simple result] (#5060)

* adding cookies to the an api route response, also when returning a simple result

* in dev server, convert a simple endpoint result into a response object

Co-authored-by: AirBorne04 <unknown>
Co-authored-by: AirBorne04 <>
Co-authored-by: Matthew Phillips <matthew@skypack.dev>
This commit is contained in:
Daniel 2022-10-18 15:52:49 +02:00 committed by GitHub
parent 04ce7f4e5c
commit 5923dd77c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 88 additions and 38 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
api routes: adding cookies to the response, also when returning a simple result

View file

@ -11,14 +11,12 @@
"astro": "astro", "astro": "astro",
"server": "node dist/server/entry.mjs" "server": "node dist/server/entry.mjs"
}, },
"devDependencies": {},
"dependencies": { "dependencies": {
"astro": "^1.5.0", "astro": "^1.5.0",
"svelte": "^3.48.0", "svelte": "^3.48.0",
"@astrojs/svelte": "^1.0.2", "@astrojs/svelte": "^1.0.2",
"@astrojs/node": "^2.0.0", "@astrojs/node": "^2.0.0",
"concurrently": "^7.2.1", "concurrently": "^7.2.1",
"lightcookie": "^1.0.25",
"unocss": "^0.15.6", "unocss": "^0.15.6",
"vite-imagetools": "^4.0.4" "vite-imagetools": "^4.0.4"
} }

View file

@ -28,6 +28,7 @@ async function get<T>(
): Promise<T> { ): Promise<T> {
const response = await fetch(`${getOrigin(incomingReq)}${endpoint}`, { const response = await fetch(`${getOrigin(incomingReq)}${endpoint}`, {
credentials: 'same-origin', credentials: 'same-origin',
headers: incomingReq.headers,
}); });
if (!response.ok) { if (!response.ok) {
// TODO make this better... // TODO make this better...

View file

@ -1,7 +0,0 @@
import lightcookie from 'lightcookie';
export function isLoggedIn(request: Request): boolean {
const cookie = request.headers.get('cookie');
const parsed = lightcookie.parse(cookie);
return 'user-id' in parsed;
}

View file

@ -1,10 +1,9 @@
import { APIContext } from 'astro'; import { APIContext } from 'astro';
import lightcookie from 'lightcookie';
import { userCartItems } from '../../models/session'; import { userCartItems } from '../../models/session';
export function get({ request }: APIContext) { export function get({ cookies }: APIContext) {
let cookie = request.headers.get('cookie'); let userId = cookies.get('user-id').value;
let userId = cookie ? lightcookie.parse(cookie)['user-id'] : '1'; // default for testing
if (!userId || !userCartItems.has(userId)) { if (!userId || !userCartItems.has(userId)) {
return { return {
body: JSON.stringify({ items: [] }), body: JSON.stringify({ items: [] }),
@ -23,11 +22,10 @@ interface AddToCartItem {
name: string; name: string;
} }
export async function post({ request }: APIContext) { export async function post({ cookies, request }: APIContext) {
const item: AddToCartItem = await request.json(); const item: AddToCartItem = await request.json();
let cookie = request.headers.get('cookie'); let userId = cookies.get('user-id').value;
let userId = lightcookie.parse(cookie)['user-id'];
if (!userCartItems.has(userId)) { if (!userCartItems.has(userId)) {
userCartItems.set(userId, new Map()); userCartItems.set(userId, new Map());

View file

@ -2,9 +2,8 @@
import Header from '../components/Header.astro'; import Header from '../components/Header.astro';
import Container from '../components/Container.astro'; import Container from '../components/Container.astro';
import { getCart } from '../api'; import { getCart } from '../api';
import { isLoggedIn } from '../models/user';
if (!isLoggedIn(Astro.request)) { if (!Astro.cookies.get('user-id').value) {
return Astro.redirect('/'); return Astro.redirect('/');
} }

View file

@ -11,6 +11,32 @@ import Container from '../components/Container.astro';
font-size: 36px; font-size: 36px;
} }
</style> </style>
<script type="module" is:inline>
document.addEventListener('DOMContentLoaded', () => {
console.log('loaded');
document.querySelector('form').addEventListener('submit', (e) => {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const data = Object.fromEntries(formData);
fetch('/login.form.async', {
method: 'POST',
body: JSON.stringify(data),
})
.then((res) => res.json())
.then((data) => {
document.querySelector("#result").innerHTML = "Progressive login was successful! you will be redirected to the store in 3 seconds";
setTimeout(
() => location.href = "/",
3000
);
});
});
});
</script>
</head> </head>
<body> <body>
<Header /> <Header />
@ -26,6 +52,7 @@ import Container from '../components/Container.astro';
<input type="submit" value="Submit" /> <input type="submit" value="Submit" />
</form> </form>
<div id="result"></div>
</Container> </Container>
</body> </body>
</html> </html>

View file

@ -0,0 +1,16 @@
import { APIContext, APIRoute } from 'astro';
export const post: APIRoute = ({ cookies, params, request }: APIContext) => {
// add a new cookie
cookies.set('user-id', '1', {
path: '/',
maxAge: 2592000,
});
return {
body: JSON.stringify({
ok: true,
user: 1,
}),
};
};

View file

@ -1,9 +0,0 @@
export function post(params, request) {
return new Response(null, {
status: 301,
headers: {
Location: '/',
'Set-Cookie': 'user-id=1; Path=/; Max-Age=2592000',
},
});
}

View file

@ -0,0 +1,16 @@
import { APIContext } from 'astro';
export function post({ cookies, params, request }: APIContext) {
// add a new cookie
cookies.set('user-id', '1', {
path: '/',
maxAge: 2592000,
});
return new Response(null, {
status: 301,
headers: {
Location: '/',
},
});
}

View file

@ -9,7 +9,7 @@ import type { LogOptions } from '../logger/core.js';
import type { RouteInfo, SSRManifest as Manifest } from './types'; import type { RouteInfo, SSRManifest as Manifest } from './types';
import mime from 'mime'; import mime from 'mime';
import { getSetCookiesFromResponse } from '../cookies/index.js'; import { attachToResponse, getSetCookiesFromResponse } from '../cookies/index.js';
import { call as callEndpoint } from '../endpoint/index.js'; import { call as callEndpoint } from '../endpoint/index.js';
import { consoleLogDestination } from '../logger/console.js'; import { consoleLogDestination } from '../logger/console.js';
import { error } from '../logger/core.js'; import { error } from '../logger/core.js';
@ -236,10 +236,14 @@ export class App {
} }
const bytes = this.#encoder.encode(body); const bytes = this.#encoder.encode(body);
headers.set('Content-Length', bytes.byteLength.toString()); headers.set('Content-Length', bytes.byteLength.toString());
return new Response(bytes, {
const response = new Response(bytes, {
status: 200, status: 200,
headers, headers,
}); });
attachToResponse(response, result.cookies);
return response;
} }
} }
} }

View file

@ -13,6 +13,7 @@ type EndpointCallResult =
type: 'simple'; type: 'simple';
body: string; body: string;
encoding?: BufferEncoding; encoding?: BufferEncoding;
cookies: AstroCookies;
} }
| { | {
type: 'response'; type: 'response';
@ -109,5 +110,6 @@ export async function call(
type: 'simple', type: 'simple',
body: response.body, body: response.body,
encoding: response.encoding, encoding: response.encoding,
cookies: context.cookies,
}; };
} }

View file

@ -5,7 +5,7 @@ import type { AstroSettings, ManifestData } from '../@types/astro';
import { DevelopmentEnvironment, SSROptions } from '../core/render/dev/index'; import { DevelopmentEnvironment, SSROptions } from '../core/render/dev/index';
import { Readable } from 'stream'; import { Readable } from 'stream';
import { getSetCookiesFromResponse } from '../core/cookies/index.js'; import { attachToResponse, getSetCookiesFromResponse } from '../core/cookies/index.js';
import { call as callEndpoint } from '../core/endpoint/dev/index.js'; import { call as callEndpoint } from '../core/endpoint/dev/index.js';
import { import {
collectErrorMetadata, collectErrorMetadata,
@ -378,8 +378,14 @@ async function handleRoute(
if (computedMimeType) { if (computedMimeType) {
contentType = computedMimeType; contentType = computedMimeType;
} }
res.writeHead(200, { 'Content-Type': `${contentType};charset=utf-8` }); const response = new Response(result.body, {
res.end(result.body); status: 200,
headers: {
'Content-Type': `${contentType};charset=utf-8`,
},
});
attachToResponse(response, result.cookies);
await writeWebResponse(res, response);
} }
} else { } else {
const result = await renderPage(options); const result = await renderPage(options);

View file

@ -260,7 +260,6 @@ importers:
'@astrojs/svelte': ^1.0.2 '@astrojs/svelte': ^1.0.2
astro: ^1.5.0 astro: ^1.5.0
concurrently: ^7.2.1 concurrently: ^7.2.1
lightcookie: ^1.0.25
svelte: ^3.48.0 svelte: ^3.48.0
unocss: ^0.15.6 unocss: ^0.15.6
vite-imagetools: ^4.0.4 vite-imagetools: ^4.0.4
@ -269,7 +268,6 @@ importers:
'@astrojs/svelte': link:../../packages/integrations/svelte '@astrojs/svelte': link:../../packages/integrations/svelte
astro: link:../../packages/astro astro: link:../../packages/astro
concurrently: 7.4.0 concurrently: 7.4.0
lightcookie: 1.0.25
svelte: 3.52.0 svelte: 3.52.0
unocss: 0.15.6 unocss: 0.15.6
vite-imagetools: 4.0.11 vite-imagetools: 4.0.11
@ -13805,10 +13803,6 @@ packages:
type-check: 0.4.0 type-check: 0.4.0
dev: true dev: true
/lightcookie/1.0.25:
resolution: {integrity: sha512-SrY/+eBPaKAMnsn7mCsoOMZzoQyCyHHHZlFCu2fjo28XxSyCLjlooKiTxyrXTg8NPaHp1YzWi0lcGG1gDi6KHw==}
dev: false
/lilconfig/2.0.6: /lilconfig/2.0.6:
resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==} resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==}
engines: {node: '>=10'} engines: {node: '>=10'}