RSS ไปยังโซเชียลเน็ตเวิร์ก 66 แห่ง: Facebook, Instagram, X, LinkedIn, Telegram และอื่นๆ บล็อก พันธมิตร (Affiliate) ติดต่อเรา
เข้าสู่ระบบ เริ่มต้นใช้งานฟรี
Updated: 2026-11-01
RedwoodJS RSS Feed: An API Function With Prisma and ETag

Short answer: A RedwoodJS app does not need an extra server to publish a feed. Generate a serverless function on the API side, read the newest published posts with Prisma, build the XML with escaped text, absolute links and real dates, return the RSS content type with cache headers and an ETag, and map a public address such as /feed.xml to the function through your host. Test the live address with curl and a validator, then connect it to an auto-poster so that every new post is shared on your social channels.

RedwoodJS is a full-stack JavaScript framework. The web side is a React application, and the API side holds GraphQL services and serverless functions that talk to a database through Prisma. That split matters for feeds. The React side runs in the browser, so it is a poor place to build XML that must be available to tools without JavaScript. The API side can answer any request with any content type, which is exactly what a feed needs. This guide builds a feed function, explains how to expose it under a clean address and ends with a test routine.

Prepare the model

A feed item needs a title, a permanent address, a date and a summary. In a Prisma model, each of them should be a field of its own, so that editors fill it in while they write.

Feed elementField in the modelRule
TitletitlePlain text, no markup
Link and identifierslug and your site addressAbsolute, https, never changes
Publication datepublishedAtSet once, when the post goes live
DescriptionsummaryOne or two complete sentences
VisibilitypublishedA boolean that editors set on purpose

Do not use the automatic update time of the record as the item date. A field that changes with every save moves old posts to the top of the feed and makes an auto-poster share them again. Keep a separate publication date that is set once. The causes and cures of repeated posts are covered in why a feed auto-posts the same article twice.

Generate the function

The Redwood command line creates a function file in the API side. Run the generator and open the new file.

yarn rw generate function feed

The generated file exports a handler that receives an event and a context and returns an object with a status code, headers and a body, in the style of the serverless platforms that Redwood deploys to. Replace its content with the following code. The details of the generator and the handler signature can change between major versions, so compare them with the documentation of the version you use.

// api/src/functions/feed.js
import { createHash } from "node:crypto";
import { db } from "src/lib/db";

const SITE = "https://example.com";

const ENT = {
  "&": "&" + "amp;",
  "<": "&" + "lt;",
  ">": "&" + "gt;",
  '"': "&" + "quot;",
  "'": "&" + "apos;",
};
const esc = (s) => String(s ?? "").replace(/[&<>"']/g, (c) => ENT[c]);

export const handler = async (event) => {
  const posts = await db.post.findMany({
    where: { published: true },
    orderBy: { publishedAt: "desc" },
    take: 20,
  });
  const newest = posts.length ? posts[0].publishedAt : new Date(0);

  const items = posts.map((p) => {
    const url = `${SITE}/blog/${p.slug}/`;
    return `<item>
      <title>${esc(p.title)}</title>
      <link>${esc(url)}</link>
      <guid isPermaLink="true">${esc(url)}</guid>
      <pubDate>${p.publishedAt.toUTCString()}</pubDate>
      <description>${esc(p.summary)}</description>
    </item>`;
  }).join("\n");

  const xml = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"><channel>
  <title>Example Journal</title>
  <link>${SITE}</link>
  <description>News and guides from Example Journal.</description>
  <lastBuildDate>${newest.toUTCString()}</lastBuildDate>
  ${items}
</channel></rss>`;

  const etag = '"' + createHash("sha1").update(xml).digest("hex") + '"';
  const headers = {
    "Content-Type": "application/rss+xml; charset=utf-8",
    "Cache-Control": "public, max-age=300",
    ETag: etag,
  };
  if (event.headers["if-none-match"] === etag) {
    return { statusCode: 304, headers, body: "" };
  }
  return { statusCode: 200, headers, body: xml };
};

Several details are deliberate. The date method of the language writes the format that the RSS specification expects. The channel date comes from the newest post and not from the clock, so that the file does not change when nothing was published. The identifier of each item is its permanent address, and the address is built from a fixed constant so that every link is absolute. The validator is a hash of the finished document, so a 304 answer saves bandwidth for you and for every tool that polls the feed. The mechanism is explained in the guide to ETags and conditional requests.

Give the feed a clean address

In development, Redwood serves functions on a separate port under the name of the file. In production, the address depends on the deployment target: some hosts expose functions under a path of their own, and others place them behind the same domain as the web side. Readers and auto-posters should not have to know any of this. Publish the feed at a short address such as /feed.xml and map it to the function with a redirect or rewrite rule of your host, then check that the rule is a rewrite and not a redirect, because a redirect adds a hop and some tools complain about it. The status codes are explained in the guide to feed status codes.

The same idea on other platforms is described in the Netlify functions guide และ the Vercel functions guide. If your Redwood project is deployed to a traditional server, the function is served by the API process, and a reverse proxy can map the clean address to it.

Keep the database healthy

Every request to the function runs a database query. An auto-poster may check the feed every minute, and a popular feed may be read by many tools, so the load can add up. Create the database client once, which the Redwood helper already does, ask for only twenty items and select only the fields the feed needs. Add an index on the columns used by the query, so that the answer stays fast when the table grows. On serverless platforms, remember that each instance opens its own connections, and a connection pool or a proxy may be needed. A slow feed can time out in the reader, as explained in the guide to feed timeouts.

Drafts, scheduling and dates

The published flag is the only gate between your editors and the world, so test it with a draft. If your app supports scheduled publishing, filter on the date as well, so that a post scheduled for tomorrow does not appear today. Import old posts with their original dates in the publication field, because a feed full of items with today’s date makes an auto-poster share the whole archive in one afternoon. For the effect of old dates see the guide to feed order and backdated posts. If you change a slug after publication, the address changes and the post looks new, so treat slugs as permanent.

Prerendering and static output

Redwood can prerender some routes into static HTML at build time. That is useful for pages, but a feed should usually stay dynamic, because it has to change when editors publish and a build is a slow way to deliver that. If you prefer a static file, write a small script that runs after each content change, generates the XML and uploads it to a storage bucket or to the public folder, then serve that file with the same headers. The dynamic function is simpler to reason about and easier to test, and a short cache already keeps the load low. Choose one approach and document it in the repository, so that the next developer knows where the feed comes from.

Images, summaries and encoding

Auto-posters build the best social posts from a feed that gives them a short summary and a picture. Store a summary on purpose, in complete sentences, instead of cutting the body automatically. If a post has a cover image, add it to the item as an enclosure with an absolute address, a type and a length. Text arrives from the database as Unicode, and the response declares UTF-8, but control characters that XML forbids can still come from pasted content, so strip them before the text goes into the template. See why special characters and emoji break feeds.

Make the feed discoverable

People and tools should not have to guess where the feed is. A Redwood app has one HTML shell, so add a link element with the relation alternate, the RSS media type and the absolute address of the feed to the head of that shell, or to the head component of the pages. A visitor or a tool that only knows your home page can then find the feed on its own. Single page applications that render in the browser can hide this tag from simple tools, so check the delivered HTML and not only what appears in the browser. The full explanation is in the guide to feed autodiscovery.

Test the feed

Request the function locally, then test the deployed address from outside, because a local test says nothing about the hosting platform and the certificate in front of your application.

curl -i http://localhost:8911/feed
curl -i https://example.com/feed.xml
curl -i -H 'If-None-Match: "paste-the-etag-here"' https://example.com/feed.xml
  • The first two requests return 200, the RSS content type and a body that starts with an XML declaration.
  • The last request returns 304 and no body when the value matches the one the server sent.
  • Every link is absolute, uses https and opens the right page.
  • Paste the address into the W3C Feed Validation Service and fix every error.
  • Publish a post, wait for the cache to expire and confirm that the new item comes first.

A longer routine is in the feed validation guide, and a shorter one in debugging a feed with curl.

Common mistakes to avoid

  • Building the feed in the browser. Tools without JavaScript see nothing.
  • The update time as the item date. Every save moves the post to the top.
  • A redirect instead of a rewrite. The public address adds a hop.
  • Unescaped text. One ampersand in a title breaks the whole document.
  • Drafts in the output. Filter by the published flag and test with a draft.
  • Only a local test. The hosting platform changes headers and caching.

How PostRSS works with a Redwood feed

PostRSS has been publishing RSS and Atom feeds to social networks since 2014. Paste the address of your feed, connect your accounts and choose how each post is built from the title, the description or the page title. PostRSS checks the feed as often as every minute and shares each new entry, with its image and link, to the channels you choose among 66 supported networks, messengers, team chats and blogs, including LinkedIn, X, Bluesky, Mastodon and Telegram. Keyword filters, UTM parameters and posting windows let you tune each channel. See the PostRSS features page and the plan limits on the pricing page. More developer guides are under the Technical Guide tag.

การอ่านที่เกี่ยวข้อง

The bottom line

A RedwoodJS feed is a function on the API side, and it has to get the details right: a query that returns only published posts, a date that is set once, escaped text, absolute links, the correct content type, a validator that lets clients skip unchanged files, a short cache and a clean public address that is a rewrite and not a redirect. Test the live address with curl and a validator, then connect it to an auto-poster. After that, every post your team publishes reaches your readers and your social channels without extra work.

FAQ

Where does a feed belong in a RedwoodJS app?

On the API side, as a serverless function. The web side runs in the browser, so it cannot reliably serve XML to tools that do not run JavaScript.

Which date should the feed use?

A publication date that is set once, when the post goes live. An update time changes with every save and would push old posts to the top of the feed.

How do I serve the feed at a clean address?

Map a short path such as /feed.xml to the function with a rewrite rule of your host, and test that it returns 200 and not a redirect.

How can I keep the database load low?

Ask for a small number of items, select only the fields you need, add an index for the query and send cache headers with a validator.

Can PostRSS read a feed served by a Redwood function?

Yes. PostRSS reads any valid RSS or Atom address that is reachable without a login. Paste the address, connect your channels and new posts are shared as soon as they appear.

New guides, once a month

What changed in the networks, what broke, and how to fix it before it costs you reach.

We send a confirmation e-mail first. Unsubscribe any time.

เครื่องมืออื่น ๆ จากทีมของเรา

พัฒนาโดย Internet Solutions ทีมผู้สร้าง PostRSS แต่ละผลิตภัณฑ์ช่วยประหยัดเวลาของคุณในแบบที่ต่างกัน

แชทสด AI สำหรับเว็บไซต์ Talkmio เว็บไซต์ของคุณตอบผู้เข้าชมได้ตลอด 24 ชั่วโมงจากเนื้อหาของคุณเอง ในภาษาของพวกเขา แพ็กเกจฟรี · ไม่ต้องใช้บัตร ผู้ช่วย AI Ask Mio แชท เขียนโค้ด ออกแบบ เขียนงาน และค้นคว้า Mio เลือกโมเดลที่ดีที่สุดให้กับแต่ละงาน แพ็กเกจฟรี ระบบอัตโนมัติ AI สำหรับบล็อกและโซเชียล AI Blog Autopilot AI เขียนบทความ SEO ยาว 2,000–3,000 คำ และแชร์แต่ละบทความไปยังโซเชียลเน็ตเวิร์กกว่า 60 แห่ง 3 บทความแรกฟรี ตรวจสุขภาพเว็บไซต์ การตรวจสอบ AI ของไซต์ SEO ความเร็ว SSL ความปลอดภัย และการตั้งค่าอีเมลในรายงานเดียว เรียงตามสิ่งที่ควรแก้ก่อน ตรวจครั้งแรกฟรี ตรวจ SEO เชิงลึก การตรวจสอบ SEO AI ของไซต์ ตรวจ SEO ทั้งเว็บใน 7 ด้าน รวมถึงการมองเห็นในการค้นหาด้วย AI พร้อมรายการแก้ไขเรียงตามผลกระทบ ตรวจครั้งแรกฟรี ฟีด RSS และฟีดสินค้า เครื่องมือสร้างฟีด RSS สร้าง RSS จากหน้าเว็บใดก็ได้ พร้อมฟีดสินค้าสำหรับ Google และ Meta ที่อัปเดตเอง แพ็กเกจฟรี พัฒนาเว็บไซต์และ SEO Internet Solutions เว็บไซต์ ร้านค้าออนไลน์ และระบบเฉพาะทาง ออกแบบ สร้าง และดูแลโดยทีมของเรา ตั้งแต่ปี 2011