RSS ไปยังโซเชียลเน็ตเวิร์ก 66 แห่ง: Facebook, Instagram, X, LinkedIn, Telegram และอื่นๆ บล็อก พันธมิตร (Affiliate) ติดต่อเรา
เข้าสู่ระบบ เริ่มต้นใช้งานฟรี
Updated: 2026-10-31
Appwrite Functions RSS Feed: Query, Escape XML and Cache

Short answer: In Appwrite, an RSS feed can be a function with a public domain. The function reads the newest published documents from a database collection, builds the XML with escaped text and absolute links, and answers with the RSS content type and a cache validator, returning a 304 status when the client already has the current version. Give the function permission for anyone to execute it, test the live address with curl and a validator, and connect it to an auto-poster so that every new document is shared on your social networks.

Appwrite is an open-source backend platform with a database, authentication, storage and functions. Teams use it behind mobile apps and small web projects, and often the content of the project, such as news, events or articles, already lives in a collection. A feed is a natural addition: the data exists, and only a public, readable view of it is missing. Appwrite Functions can provide that view without a separate server. The details that make a feed reliable are the same as anywhere else: escaped text, absolute links, dates in the right format and an identifier that never changes. This guide builds a complete function, explains how to expose it and ends with a test routine.

Plan the data

A feed item needs a title, a permanent address, a publication date and a summary. Create a collection for posts with attributes for each, and keep the slug separate from the title so that it never changes after the first save.

AttributeประเภทRule
slugString, unique indexSet once, never edited
titleStringPlain text
summaryStringOne or two complete sentences
publishedBooleanFalse for drafts
publishedAtDatetime, indexedThe moment the post goes live

Add an index on the date attribute, because the function sorts by it. The published flag is a safety switch: an editor can prepare a document in advance and switch the flag only when the page on the website is live. Keeping the data model this small also makes the function easy to reason about.

Create the function

Create a function with a current Node.js runtime and give it the scope that allows reading documents. Appwrite can provide the function with a temporary key for each execution, so you do not have to store a secret in the code. The same idea for other serverless platforms is covered in the Netlify Functions feed guide และ the Firebase Cloud Functions feed guide.

// src/main.js
import { Client, Databases, Query } from "node-appwrite";
import { createHash } from "node:crypto";

const SITE = "https://example.com";
const DATABASE_ID = "main";
const COLLECTION_ID = "posts";

export default async ({ req, res, error }) => {
  if (req.path !== "/feed.xml") {
    return res.text("Not found", 404);
  }

  const client = new Client()
    .setEndpoint(process.env.APPWRITE_FUNCTION_API_ENDPOINT)
    .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
    .setKey(req.headers["x-appwrite-key"]);
  const databases = new Databases(client);

  // the code from the next sections goes here
};

One function answers every path on its domain, so the first lines return a 404 status for anything other than the feed address. Environment variable names and header names may differ between versions of the platform, so check them in the documentation of the version that you run.

Query only published documents

Ask the database for the newest published documents and nothing else. Never put drafts or future posts into the list.

const list = await databases.listDocuments(DATABASE_ID, COLLECTION_ID, [
  Query.equal("published", true),
  Query.lessThanEqual("publishedAt", new Date().toISOString()),
  Query.orderDesc("publishedAt"),
  Query.limit(20),
]);
const posts = list.documents;

The query has three jobs: leave out anything that is not published, put the newest first and keep the document short. Twenty items are enough for a reader or an auto-poster, and a short file is fetched quickly.

Build the XML safely

Text from a database can contain ampersands, angle brackets and quotation marks, and any of them can break an XML document. Escape every value before it goes into the template.

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

const newest = posts.length ? new Date(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>${new Date(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>`;

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 every link is absolute.

Answer with the right headers

The function returns the XML with the RSS content type and a cache lifetime, and it answers with a 304 status when the validator that the client sends matches the current document.

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 (req.headers["if-none-match"] === etag) {
  return res.send("", 304, headers);
}
return res.text(xml, 200, headers);

The validator is a hash of the finished document, so it changes exactly when the content changes. 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, and the status codes in the guide to feed status codes.

Make the function public

A feed must be readable without a login, so two settings matter. In the settings of the function, give the role for any user permission to execute it. Then add a domain to the function, either the one that the platform generates or your own. Open the address in a private window and check that you receive XML and not an error about permissions. If you use your own domain, point a record at the platform and wait for the certificate to be issued before you give the address to anyone. A feed that works for you while you are signed in to the console can still fail for everybody else, which is why this test is not optional.

Dates, drafts and old posts

The query already keeps drafts and future posts out. That matters, because a draft that leaks into the feed is shared on social networks before it exists on your website. If you import old posts, give them their original dates, because a feed full of items with today’s date makes an auto-poster share your whole archive in one afternoon. For the effect of old dates see the guide to feed order and backdated posts.

Cold starts and limits

Functions that run on demand may need a moment to start when nobody has called them for a while. A feed that is polled every few minutes keeps the function warm, but the first request after a quiet night can be slower. Auto-posters wait longer than people, so this is rarely a problem, yet it is one more reason to keep the code small and the query simple. Check the execution time limit and the memory settings of the function, and look at the execution log after the first week: a failing query or a missing permission shows up there before anyone complains.

Summaries, images and encoding

Auto-posters build the best social posts from a feed that gives them a short summary and a picture. Write a real summary for every document instead of cutting the text automatically, because an automatic cut can end in the middle of a sentence and that is exactly what the auto-poster will copy. If a post has an image, store its public address in the collection, or build it from a file in Appwrite storage that is readable by anyone, and add it to the item as an enclosure with 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 when you save the document. See why special characters and emoji break feeds. Finally, make the function easy to find: add a link element to the head of your website, with the relation set to alternate, the type set to the RSS media type and the absolute address of the feed, as explained in the guide to feed autodiscovery.

Test the feed

Request the live address, then look at the result instead of assuming that it is right.

curl -i https://feed.example.com/feed.xml
curl -i -H 'If-None-Match: "paste-the-etag-here"' https://feed.example.com/feed.xml
  • The first request returns 200, the RSS content type and a body that starts with an XML declaration.
  • The second returns 304 and no body when the value matches the one the server sent.
  • Every link is absolute, uses https and points to your real domain.
  • Paste the address into the W3C Feed Validation Service and fix every error.
  • Publish a document, reload the feed 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

  • No execute permission for anyone. The auto-poster receives an error.
  • Unescaped text. One ampersand in a title breaks the whole document.
  • The clock as the channel date. The file changes on every request and caching stops working.
  • Slugs that follow titles. An edit changes the address and the post may be shared twice.
  • Drafts in the list. An article is shared before it exists on the website.
  • Testing only while signed in. Use a private window and curl.

How PostRSS works with an Appwrite 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

An Appwrite feed is one function with a public domain, but it has to get the details right: a query that returns only published documents with stable slugs, escaped text, absolute links, a channel date taken from the newest post, the correct content type and a validator that lets clients skip unchanged files. Give anyone permission to execute it, test the live address with curl and a validator, then connect it to an auto-poster. After that, every post you publish reaches your readers and your social channels without extra work.

FAQ

Can an Appwrite function return an RSS feed?

Yes. A function can return text with any content type and status code, so it can answer with XML and the RSS media type when it is called through its domain.

How do I make the function readable without a login?

Give the role for any user permission to execute the function, add a domain to it and test the address in a private window.

Do I need to store an API key in the code?

Not necessarily. The platform can provide a temporary key to each execution if the function has the right scopes. Never put a permanent secret key in a public repository.

How do conditional requests work in a function?

The function sends a hash of the document as the ETag header. When the client sends the same value back, the function answers with a 304 status and no body.

Can PostRSS read a feed served by an Appwrite 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