wix-cli-backend-api
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWix Backend API Builder
Wix Backend API 构建工具
Creates Astro server endpoint extensions for Wix CLI applications. Backend APIs are server-side routes that handle HTTP requests, process data, and return responses. They are automatically discovered and don't require extension registration. Endpoints are generated based on API specifications and are designed to integrate well with frontend applications in fullstack applications.
为Wix CLI应用创建Astro服务器端点扩展。后端API是处理HTTP请求、处理数据并返回响应的服务器端路由。它们会被自动发现,无需进行扩展注册。端点基于API规范生成,旨在与全栈应用中的前端应用良好集成。
Architecture
架构
Astro server endpoints are TypeScript files ( extension) in the directory that export named functions for HTTP methods. They are automatically converted to API routes.
.tssrc/pages/api/Key characteristics:
- Files use the extension
.ts - Files export named functions: ,
GET,POST,PUT,DELETEPATCH - Always import type from 'astro' for proper typing
APIRoute - Always return objects
Response - Use async/await for asynchronous operations
- No extension registration needed (auto-discovered)
Astro服务器端点是目录下的TypeScript文件(扩展名),导出HTTP方法对应的命名函数。它们会被自动转换为API路由。
src/pages/api/.ts核心特性:
- 文件使用扩展名
.ts - 文件导出命名函数:、
GET、POST、PUT、DELETEPATCH - 必须从'astro'导入类型以获得正确的类型提示
APIRoute - 始终返回对象
Response - 异步操作使用async/await
- 无需扩展注册(自动发现)
File Structure and Naming
文件结构与命名
Basic Endpoint
基础端点
File path determines the endpoint URL:
src/pages/api/users.ts → /api/users文件路径决定端点URL:
src/pages/api/users.ts → /api/usersDynamic Routes
动态路由
Use square brackets for dynamic parameters:
src/pages/api/users/[id].ts → /api/users/:id
src/pages/api/posts/[slug].ts → /api/posts/:slug
src/pages/api/users/[userId]/posts/[postId].ts → /api/users/:userId/posts/:postId使用方括号定义动态参数:
src/pages/api/users/[id].ts → /api/users/:id
src/pages/api/posts/[slug].ts → /api/posts/:slug
src/pages/api/users/[userId]/posts/[postId].ts → /api/users/:userId/posts/:postIdHTTP Methods
HTTP方法
Export named functions for each HTTP method you want to support. Always import the type from 'astro' for proper typing:
APIRoutetypescript
import type { APIRoute } from "astro";
export async function GET({ params, request }) {
// Handle GET request
}
export async function POST({ params, request }) {
// Handle POST request
}
export async function PUT({ params, request }) {
// Handle PUT request
}
export async function DELETE({ params, request }) {
// Handle DELETE request
}
export async function PATCH({ params, request }) {
// Handle PATCH request
}为每个需要支持的HTTP方法导出命名函数。必须从'astro'导入类型以获得正确的类型提示:
APIRoutetypescript
import type { APIRoute } from "astro";
export async function GET({ params, request }) {
// Handle GET request
}
export async function POST({ params, request }) {
// Handle POST request
}
export async function PUT({ params, request }) {
// Handle PUT request
}
export async function DELETE({ params, request }) {
// Handle DELETE request
}
export async function PATCH({ params, request }) {
// Handle PATCH request
}Request Handling
请求处理
Path Parameters
路径参数
Extract dynamic route parameters from :
paramstypescript
export async function GET({ params }) {
const { id } = params; // From /api/users/[id]
if (!id) {
return new Response(JSON.stringify({ error: "ID required" }), {
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
});
}
// Use id to fetch data
}从中提取动态路由参数:
paramstypescript
export async function GET({ params }) {
const { id } = params; // From /api/users/[id]
if (!id) {
return new Response(JSON.stringify({ error: "ID required" }), {
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
});
}
// Use id to fetch data
}Query Parameters
查询参数
Extract query string parameters from using :
request.urlnew URL(request.url).searchParamstypescript
export async function GET({ request }) {
const url = new URL(request.url);
const search = url.searchParams.get("search");
const limit = parseInt(url.searchParams.get("limit") || "10", 10);
const offset = parseInt(url.searchParams.get("offset") || "0", 10);
// Use query parameters
}Note: Use to access the full URL, and for query parameters.
request.urlnew URL(request.url).searchParams使用从中提取查询字符串参数:
new URL(request.url).searchParamsrequest.urltypescript
export async function GET({ request }) {
const url = new URL(request.url);
const search = url.searchParams.get("search");
const limit = parseInt(url.searchParams.get("limit") || "10", 10);
const offset = parseInt(url.searchParams.get("offset") || "0", 10);
// Use query parameters
}注意: 使用访问完整URL,使用获取查询参数。
request.urlnew URL(request.url).searchParamsRequest Body
请求体
Parse JSON body from POST/PUT requests:
typescript
export async function POST({ request }) {
try {
const body = await request.json();
const { title, content } = body;
// Validate required fields
if (!title || !content) {
return new Response(
JSON.stringify({ error: "Title and content required" }),
{
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
}
);
}
// Process data
} catch (error) {
return new Response(JSON.stringify({ error: "Invalid JSON" }), {
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
});
}
}解析POST/PUT请求的JSON体:
typescript
export async function POST({ request }) {
try {
const body = await request.json();
const { title, content } = body;
// Validate required fields
if (!title || !content) {
return new Response(
JSON.stringify({ error: "Title and content required" }),
{
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
}
);
}
// Process data
} catch (error) {
return new Response(JSON.stringify({ error: "Invalid JSON" }), {
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
});
}
}Headers
请求头
Access request headers:
typescript
export async function GET({ request }) {
const authHeader = request.headers.get("Authorization");
const contentType = request.headers.get("Content-Type");
// Use headers
}访问请求头:
typescript
export async function GET({ request }) {
const authHeader = request.headers.get("Authorization");
const contentType = request.headers.get("Content-Type");
// Use headers
}Response Patterns
响应模式
Always return a object with appropriate status codes and headers. Use for JSON responses:
ResponseJSON.stringify()始终返回带有适当状态码和请求头的对象。JSON响应使用处理:
ResponseJSON.stringify()Success Response
成功响应
typescript
return new Response(JSON.stringify({ data: result }), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});typescript
return new Response(JSON.stringify({ data: result }), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});Created Response
创建成功响应
typescript
return new Response(JSON.stringify({ id: newId, ...data }), {
status: 201,
headers: {
"Content-Type": "application/json",
},
});typescript
return new Response(JSON.stringify({ id: newId, ...data }), {
status: 201,
headers: {
"Content-Type": "application/json",
},
});Error Responses
错误响应
typescript
// Bad Request (400)
return new Response(JSON.stringify({ error: "Invalid input" }), {
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
});
// Not Found (404)
return new Response(JSON.stringify({ error: "Resource not found" }), {
status: 404,
statusText: "Not Found",
headers: { "Content-Type": "application/json" },
});
// Internal Server Error (500)
return new Response(JSON.stringify({ error: "Internal server error" }), {
status: 500,
statusText: "Internal Server Error",
headers: { "Content-Type": "application/json" },
});typescript
// Bad Request (400)
return new Response(JSON.stringify({ error: "Invalid input" }), {
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
});
// Not Found (404)
return new Response(JSON.stringify({ error: "Resource not found" }), {
status: 404,
statusText: "Not Found",
headers: { "Content-Type": "application/json" },
});
// Internal Server Error (500)
return new Response(JSON.stringify({ error: "Internal server error" }), {
status: 500,
statusText: "Internal Server Error",
headers: { "Content-Type": "application/json" },
});Wix Data Integration
Wix Data 集成
Use SDK to interact with Wix Data collections:
@wix/datatypescript
import { items } from "@wix/data";
export async function GET({ params }) {
const { id } = params;
try {
if (id) {
// Get single item
const item = await items.get("collectionId", id);
return new Response(JSON.stringify(item), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} else {
// Get all items
const results = await items.query("collectionId").limit(50).find();
return new Response(JSON.stringify(results.items), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
} catch (error) {
return new Response(JSON.stringify({ error: "Failed to fetch data" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}
export async function POST({ request }) {
try {
const body = await request.json();
const newItem = await items.insert("collectionId", body);
return new Response(JSON.stringify(newItem), {
status: 201,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
return new Response(JSON.stringify({ error: "Failed to create item" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}
export async function PUT({ params, request }) {
const { id } = params;
if (!id) {
return new Response(JSON.stringify({ error: "ID required" }), {
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
});
}
try {
const body = await request.json();
const updatedItem = await items.update("collectionId", {
_id: id,
...body,
});
return new Response(JSON.stringify(updatedItem), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
return new Response(JSON.stringify({ error: "Failed to update item" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}
export async function DELETE({ params }) {
const { id } = params;
if (!id) {
return new Response(JSON.stringify({ error: "ID required" }), {
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
});
}
try {
await items.remove("collectionId", id);
return new Response(null, {
status: 204,
});
} catch (error) {
return new Response(JSON.stringify({ error: "Failed to delete item" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}Query methods: , , , , , , , , , , , , , , , , , , , , ,
eqnegtgeltlebetweencontainsstartsWithendsWithhasSomehasAllisEmptyisNotEmptyandornotascendingdescendinglimitskipinclude使用 SDK与Wix Data集合交互:
@wix/datatypescript
import { items } from "@wix/data";
export async function GET({ params }) {
const { id } = params;
try {
if (id) {
// Get single item
const item = await items.get("collectionId", id);
return new Response(JSON.stringify(item), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} else {
// Get all items
const results = await items.query("collectionId").limit(50).find();
return new Response(JSON.stringify(results.items), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
} catch (error) {
return new Response(JSON.stringify({ error: "Failed to fetch data" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}
export async function POST({ request }) {
try {
const body = await request.json();
const newItem = await items.insert("collectionId", body);
return new Response(JSON.stringify(newItem), {
status: 201,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
return new Response(JSON.stringify({ error: "Failed to create item" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}
export async function PUT({ params, request }) {
const { id } = params;
if (!id) {
return new Response(JSON.stringify({ error: "ID required" }), {
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
});
}
try {
const body = await request.json();
const updatedItem = await items.update("collectionId", {
_id: id,
...body,
});
return new Response(JSON.stringify(updatedItem), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
return new Response(JSON.stringify({ error: "Failed to update item" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}
export async function DELETE({ params }) {
const { id } = params;
if (!id) {
return new Response(JSON.stringify({ error: "ID required" }), {
status: 400,
statusText: "Bad Request",
headers: { "Content-Type": "application/json" },
});
}
try {
await items.remove("collectionId", id);
return new Response(null, {
status: 204,
});
} catch (error) {
return new Response(JSON.stringify({ error: "Failed to delete item" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}查询方法: , , , , , , , , , , , , , , , , , , , , ,
eqnegtgeltlebetweencontainsstartsWithendsWithhasSomehasAllisEmptyisNotEmptyandornotascendingdescendinglimitskipincludeOutput Structure
输出结构
src/pages/api/
├── users.ts # /api/users endpoint
├── users/
│ └── [id].ts # /api/users/:id endpoint
└── posts.ts # /api/posts endpointsrc/pages/api/
├── users.ts # /api/users endpoint
├── users/
│ └── [id].ts # /api/users/:id endpoint
└── posts.ts # /api/posts endpointExamples
示例
For additional examples, see references/backend-api-examples.md.
更多示例请参考references/backend-api-examples.md。
Extension Registration
扩展注册
Backend API endpoints do NOT require extension registration. They are automatically discovered from the directory structure.
src/pages/api/后端API端点无需进行扩展注册。 它们会从目录结构中自动被发现。
src/pages/api/Verification
验证
After implementation, use wix-cli-app-validation to validate TypeScript compilation, build, preview, and runtime behavior.
实现完成后,使用wix-cli-app-validation验证TypeScript编译、构建、预览和运行时行为。
Code Quality Requirements
代码质量要求
- Strict TypeScript (no , explicit return types)
any - Import type from 'astro' for proper typing
APIRoute - Always return objects
Response - Use for JSON responses
JSON.stringify() - Use proper HTTP status codes (200, 201, 400, 404, 500, etc.)
- Include proper headers ()
Content-Type: application/json - Include in error responses for clarity
statusText - Handle errors gracefully with try/catch blocks
- Validate input parameters and request bodies
- Use async/await for asynchronous operations
- Keep endpoints focused and single-purpose
- No comments
@ts-ignore
- 严格TypeScript(禁止使用,明确返回类型)
any - 从'astro'导入类型以获得正确的类型提示
APIRoute - 始终返回对象
Response - JSON响应使用处理
JSON.stringify() - 使用正确的HTTP状态码(200、201、400、404、500等)
- 包含正确的请求头()
Content-Type: application/json - 错误响应中包含以提升清晰度
statusText - 使用try/catch块优雅处理错误
- 验证输入参数和请求体
- 异步操作使用async/await
- 保持端点聚焦,单一职责
- 禁止使用注释
@ts-ignore