Skip to content

Commit cb95aa5

Browse files
authored
Update rss package to return a response (#8198)
1 parent 353dcb2 commit cb95aa5

4 files changed

Lines changed: 113 additions & 30 deletions

File tree

.changeset/honest-houses-deny.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
'@astrojs/rss': major
3+
---
4+
5+
Update the `rss()` default export to return a `Response` instead of a simple object, which is deprecated in Astro 3.0. If you were directly returning the `rss()` result from an endpoint before, this breaking change should not affect you.
6+
7+
You can also import `getRssString()` to get the RSS string directly and use it to return your own Response:
8+
9+
```ts
10+
// src/pages/rss.xml.js
11+
import { getRssString } from '@astrojs/rss';
12+
13+
export async function get(context) {
14+
const rssString = await getRssString({
15+
title: 'Buzz’s Blog',
16+
...
17+
});
18+
19+
return new Response(rssString, {
20+
headers: {
21+
'Content-Type': 'application/xml',
22+
},
23+
});
24+
}
25+
```

packages/astro-rss/README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,27 @@ export async function get(context) {
370370
}
371371
```
372372
373-
---
373+
## `getRssString()`
374+
375+
As `rss()` returns a `Response`, you can also use `getRssString()` to get the RSS string directly and use it in your own response:
376+
377+
```ts "getRssString"
378+
// src/pages/rss.xml.js
379+
import { getRssString } from '@astrojs/rss';
380+
381+
export async function get(context) {
382+
const rssString = await getRssString({
383+
title: 'Buzz’s Blog',
384+
...
385+
});
386+
387+
return new Response(rssString, {
388+
headers: {
389+
'Content-Type': 'application/xml',
390+
},
391+
});
392+
}
393+
```
374394
375395
For more on building with Astro, [visit the Astro docs][astro-rss].
376396

packages/astro-rss/src/index.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,18 @@ const rssOptionsValidator = z.object({
9898
trailingSlash: z.boolean().default(true),
9999
});
100100

101-
export default async function getRSS(rssOptions: RSSOptions) {
102-
const validatedRssOptions = await validateRssOptions(rssOptions);
101+
export default async function getRssResponse(rssOptions: RSSOptions): Promise<Response> {
102+
const rssString = await getRssString(rssOptions);
103+
return new Response(rssString, {
104+
headers: {
105+
'Content-Type': 'application/xml',
106+
},
107+
});
108+
}
103109

104-
return {
105-
body: await generateRSS(validatedRssOptions),
106-
};
110+
export async function getRssString(rssOptions: RSSOptions): Promise<string> {
111+
const validatedRssOptions = await validateRssOptions(rssOptions);
112+
return await generateRSS(validatedRssOptions);
107113
}
108114

109115
async function validateRssOptions(rssOptions: RSSOptions) {

packages/astro-rss/test/rss.test.js

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import rss from '../dist/index.js';
1+
import rss, { getRssString } from '../dist/index.js';
22
import { rssSchema } from '../dist/schema.js';
33
import chai from 'chai';
44
import chaiPromises from 'chai-as-promised';
@@ -36,41 +36,73 @@ const validXmlWithStylesheet = `<?xml version="1.0" encoding="UTF-8"?><?xml-styl
3636
const validXmlWithXSLStylesheet = `<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/feedstylesheet.xsl" type="text/xsl"?><rss version="2.0"><channel><title><![CDATA[${title}]]></title><description><![CDATA[${description}]]></description><link>${site}/</link></channel></rss>`;
3737

3838
describe('rss', () => {
39+
it('should return a response', async () => {
40+
const response = await rss({
41+
title,
42+
description,
43+
items: [phpFeedItem, web1FeedItem],
44+
site,
45+
});
46+
47+
const str = await response.text();
48+
chai.expect(str).xml.to.equal(validXmlResult);
49+
50+
const contentType = response.headers.get('Content-Type');
51+
chai.expect(contentType).to.equal('application/xml');
52+
});
53+
54+
it('should be the same string as getRssString', async () => {
55+
const options = {
56+
title,
57+
description,
58+
items: [phpFeedItem, web1FeedItem],
59+
site,
60+
};
61+
62+
const response = await rss(options);
63+
const str1 = await response.text();
64+
const str2 = await getRssString(options);
65+
66+
chai.expect(str1).to.equal(str2);
67+
});
68+
});
69+
70+
describe('getRssString', () => {
3971
it('should generate on valid RSSFeedItem array', async () => {
40-
const { body } = await rss({
72+
const str = await getRssString({
4173
title,
4274
description,
4375
items: [phpFeedItem, web1FeedItem],
4476
site,
4577
});
4678

47-
chai.expect(body).xml.to.equal(validXmlResult);
79+
chai.expect(str).xml.to.equal(validXmlResult);
4880
});
4981

5082
it('should generate on valid RSSFeedItem array with HTML content included', async () => {
51-
const { body } = await rss({
83+
const str = await getRssString({
5284
title,
5385
description,
5486
items: [phpFeedItemWithContent, web1FeedItemWithContent],
5587
site,
5688
});
5789

58-
chai.expect(body).xml.to.equal(validXmlWithContentResult);
90+
chai.expect(str).xml.to.equal(validXmlWithContentResult);
5991
});
6092

6193
it('should generate on valid RSSFeedItem array with all RSS content included', async () => {
62-
const { body } = await rss({
94+
const str = await getRssString({
6395
title,
6496
description,
6597
items: [phpFeedItem, web1FeedItemWithAllData],
6698
site,
6799
});
68100

69-
chai.expect(body).xml.to.equal(validXmlResultWithAllData);
101+
chai.expect(str).xml.to.equal(validXmlResultWithAllData);
70102
});
71103

72104
it('should generate on valid RSSFeedItem array with custom data included', async () => {
73-
const { body } = await rss({
105+
const str = await getRssString({
74106
xmlns: {
75107
dc: 'http://purl.org/dc/elements/1.1/',
76108
},
@@ -80,37 +112,37 @@ describe('rss', () => {
80112
site,
81113
});
82114

83-
chai.expect(body).xml.to.equal(validXmlWithCustomDataResult);
115+
chai.expect(str).xml.to.equal(validXmlWithCustomDataResult);
84116
});
85117

86118
it('should include xml-stylesheet instruction when stylesheet is defined', async () => {
87-
const { body } = await rss({
119+
const str = await getRssString({
88120
title,
89121
description,
90122
items: [],
91123
site,
92124
stylesheet: '/feedstylesheet.css',
93125
});
94126

95-
chai.expect(body).xml.to.equal(validXmlWithStylesheet);
127+
chai.expect(str).xml.to.equal(validXmlWithStylesheet);
96128
});
97129

98130
it('should include xml-stylesheet instruction with xsl type when stylesheet is set to xsl file', async () => {
99-
const { body } = await rss({
131+
const str = await getRssString({
100132
title,
101133
description,
102134
items: [],
103135
site,
104136
stylesheet: '/feedstylesheet.xsl',
105137
});
106138

107-
chai.expect(body).xml.to.equal(validXmlWithXSLStylesheet);
139+
chai.expect(str).xml.to.equal(validXmlWithXSLStylesheet);
108140
});
109141

110142
it('should preserve self-closing tags on `customData`', async () => {
111143
const customData =
112144
'<atom:link href="https://example.com/feed.xml" rel="self" type="application/rss+xml"/>';
113-
const { body } = await rss({
145+
const str = await getRssString({
114146
title,
115147
description,
116148
items: [],
@@ -121,34 +153,34 @@ describe('rss', () => {
121153
customData,
122154
});
123155

124-
chai.expect(body).to.contain(customData);
156+
chai.expect(str).to.contain(customData);
125157
});
126158

127159
it('should filter out entries marked as `draft`', async () => {
128-
const { body } = await rss({
160+
const str = await getRssString({
129161
title,
130162
description,
131163
items: [phpFeedItem, { ...web1FeedItem, draft: true }],
132164
site,
133165
});
134166

135-
chai.expect(body).xml.to.equal(validXmlWithoutWeb1FeedResult);
167+
chai.expect(str).xml.to.equal(validXmlWithoutWeb1FeedResult);
136168
});
137169

138170
it('should respect drafts option', async () => {
139-
const { body } = await rss({
171+
const str = await getRssString({
140172
title,
141173
description,
142174
items: [phpFeedItem, { ...web1FeedItem, draft: true }],
143175
site,
144176
drafts: true,
145177
});
146178

147-
chai.expect(body).xml.to.equal(validXmlResult);
179+
chai.expect(str).xml.to.equal(validXmlResult);
148180
});
149181

150182
it('should not append trailing slash to URLs with the given option', async () => {
151-
const { body } = await rss({
183+
const str = await getRssString({
152184
title,
153185
description,
154186
items: [phpFeedItem, { ...web1FeedItem, draft: true }],
@@ -157,8 +189,8 @@ describe('rss', () => {
157189
trailingSlash: false,
158190
});
159191

160-
chai.expect(body).xml.to.contain('https://example.com/<');
161-
chai.expect(body).xml.to.contain('https://example.com/php<');
192+
chai.expect(str).xml.to.contain('https://example.com/<');
193+
chai.expect(str).xml.to.contain('https://example.com/php<');
162194
});
163195

164196
it('Deprecated import.meta.glob mapping still works', async () => {
@@ -187,14 +219,14 @@ describe('rss', () => {
187219
),
188220
};
189221

190-
const { body } = await rss({
222+
const str = await getRssString({
191223
title,
192224
description,
193225
items: globResult,
194226
site,
195227
});
196228

197-
chai.expect(body).xml.to.equal(validXmlResult);
229+
chai.expect(str).xml.to.equal(validXmlResult);
198230
});
199231

200232
it('should fail when an invalid date string is provided', async () => {

0 commit comments

Comments
 (0)