hashnode
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCall the Hashnode Public GraphQL API with . The user's Personal
Access Token is in . Single endpoint:
(always a JSON body ).
curl + jq$HASHNODE_TOKENhttps://gql.hashnode.comPOST{query, variables}Every request needs these headers:
Authorization: $HASHNODE_TOKEN # raw token — NO "Bearer " prefix
Content-Type: application/jsonGraphQL always returns HTTP ; real failures live in the JSON
array — always inspect it and show it verbatim. An entry mentioning
/ means the token is invalid → the user must
re-connect the Hashnode connector.
200errorserrorsUnauthorizednot authenticatedHelper — send a query/mutation ( = query string, = variables JSON):
$1$2bash
gql() {
jq -n --arg q "$1" --argjson v "${2:-null}" '{query:$q, variables:$v}' \
| curl -sS -X POST https://gql.hashnode.com \
-H "Authorization: $HASHNODE_TOKEN" \
-H "Content-Type: application/json" \
-d @-
}使用调用Hashnode Public GraphQL API。用户的个人访问令牌存储在中。唯一的端点是:(始终以方式发送JSON请求体)。
curl + jq$HASHNODE_TOKENhttps://gql.hashnode.comPOST{query, variables}每个请求都需要以下请求头:
Authorization: $HASHNODE_TOKEN # raw token — NO "Bearer " prefix
Content-Type: application/jsonGraphQL始终返回HTTP 状态码;真正的错误信息存在于JSON的数组中——务必检查该数组并原样展示。如果条目提到 / ,说明令牌无效→用户必须重新连接Hashnode连接器。
200errorserrorsUnauthorizednot authenticated辅助函数——发送查询/变更请求( = 查询字符串, = 变量JSON):
$1$2bash
gql() {
jq -n --arg q "$1" --argjson v "${2:-null}" '{query:$q, variables:$v}' \
| curl -sS -X POST https://gql.hashnode.com \
-H "Authorization: $HASHNODE_TOKEN" \
-H "Content-Type: application/json" \
-d @-
}Always start by confirming the token and finding the publication id
始终先确认令牌并获取出版物ID
publishPostcreateDraftpublicationIdbash
gql 'query { me { id username publications(first: 10) { edges { node { id title url } } } } }' \
| jq '{me: .data.me.username, publications: [.data.me.publications.edges[].node | {id, title, url}], errors: .errors}'Pick the target blog's (that is the ). If the user has
exactly one publication, use it; otherwise ask which blog to post to.
idpublicationIdpublishPostcreateDraftpublicationIdbash
gql 'query { me { id username publications(first: 10) { edges { node { id title url } } } } }' \
| jq '{me: .data.me.username, publications: [.data.me.publications.edges[].node | {id, title, url}], errors: .errors}'选择目标博客的(即)。如果用户只有一个出版物,则直接使用;否则询问用户要发布到哪个博客。
idpublicationIdPublish a post
发布文章
Confirm with the user before publishing publicly. If they are not sure, save
a draft first (see below). is required — supply 1–5 tags, each as
(slug lowercase, no spaces).
tags{name, slug}bash
PUB_ID="PUBLICATION_ID" # from the me query above
TITLE="My title"
BODY_MD="$(cat article.md)" # full Markdown body
VARS=$(jq -n --arg p "$PUB_ID" --arg t "$TITLE" --arg b "$BODY_MD" '{
input: {
publicationId: $p,
title: $t,
contentMarkdown: $b,
tags: [{name:"AI", slug:"ai"}, {name:"Web Development", slug:"web-development"}]
}
}')
gql 'mutation PublishPost($input: PublishPostInput!) {
publishPost(input: $input) { post { id slug url title } }
}' "$VARS" | jq '{post: .data.publishPost.post, errors: .errors}'Useful optional fields:
input- — post subtitle.
subtitle - — custom URL slug (otherwise derived from the title).
slug - /
canonicalUrl— when cross-posting, point SEO back to the original source. Set this whenever the same article also lives elsewhere.originalArticleURL - — cover image.
coverImageOptions: { coverImageURL: "https://..." } - — ISO-8601 timestamp to backdate;
publishedAtetc. live underdisableComments.settings
**发布公开文章前请与用户确认。**如果用户不确定,先保存为草稿(见下文)。是必填项——提供1–5个标签,每个标签格式为(slug为小写,无空格)。
tags{name, slug}bash
PUB_ID="PUBLICATION_ID" # 来自上述me查询
TITLE="My title"
BODY_MD="$(cat article.md)" # 完整Markdown内容
VARS=$(jq -n --arg p "$PUB_ID" --arg t "$TITLE" --arg b "$BODY_MD" '{
input: {
publicationId: $p,
title: $t,
contentMarkdown: $b,
tags: [{name:"AI", slug:"ai"}, {name:"Web Development", slug:"web-development"}]
}
}')
gql 'mutation PublishPost($input: PublishPostInput!) {
publishPost(input: $input) { post { id slug url title } }
}' "$VARS" | jq '{post: .data.publishPost.post, errors: .errors}'实用的可选字段:
input- — 文章副标题。
subtitle - — 自定义URL路径(否则从标题自动生成)。
slug - /
canonicalUrl— 交叉发布时,将SEO权重指向原始来源。只要同一文章还发布在其他地方,就设置该字段。originalArticleURL - — 封面图片。
coverImageOptions: { coverImageURL: "https://..." } - — ISO-8601时间戳用于回溯发布时间;
publishedAt等选项位于disableComments字段下。settings
Save a draft (safe, non-public)
保存草稿(安全,非公开)
Use this when the user has not explicitly approved public publishing:
bash
VARS=$(jq -n --arg p "$PUB_ID" --arg t "$TITLE" --arg b "$BODY_MD" '{
input: { publicationId: $p, title: $t, contentMarkdown: $b }
}')
gql 'mutation CreateDraft($input: CreateDraftInput!) {
createDraft(input: $input) { draft { id slug title } }
}' "$VARS" | jq '{draft: .data.createDraft.draft, errors: .errors}'当用户未明确批准公开发布时使用此方法:
bash
VARS=$(jq -n --arg p "$PUB_ID" --arg t "$TITLE" --arg b "$BODY_MD" '{
input: { publicationId: $p, title: $t, contentMarkdown: $b }
}')
gql 'mutation CreateDraft($input: CreateDraftInput!) {
createDraft(input: $input) { draft { id slug title } }
}' "$VARS" | jq '{draft: .data.createDraft.draft, errors: .errors}'Update a published post
更新已发布的文章
updatePostidpublishPostbash
VARS=$(jq -n --arg id "POST_ID" --arg b "$(cat article.md)" '{
input: { id: $id, contentMarkdown: $b }
}')
gql 'mutation UpdatePost($input: UpdatePostInput!) {
updatePost(input: $input) { post { id url title } }
}' "$VARS" | jq '{post: .data.updatePost.post, errors: .errors}'updatePostidpublishPostbash
VARS=$(jq -n --arg id "POST_ID" --arg b "$(cat article.md)" '{
input: { id: $id, contentMarkdown: $b }
}')
gql 'mutation UpdatePost($input: UpdatePostInput!) {
updatePost(input: $input) { post { id url title } }
}' "$VARS" | jq '{post: .data.updatePost.post, errors: .errors}'List / inspect my posts
列出/查看我的文章
bash
gql 'query { me { posts(pageSize: 20, page: 1) { nodes { id title slug url views reactionCount responseCount publishedAt } } } }' \
| jq '[.data.me.posts.nodes[] | {id, title, url, views, reactions: .reactionCount, responses: .responseCount}]'Single post with full content + stats:
bash
gql 'query GetPost($id: ObjectId!) { post(id: $id) { title url views reactionCount responseCount content { markdown } } }' \
"$(jq -n --arg id "POST_ID" '{id:$id}')" | jq '.data.post | {title, url, views, reactions: .reactionCount}'bash
gql 'query { me { posts(pageSize: 20, page: 1) { nodes { id title slug url views reactionCount responseCount publishedAt } } } }' \
| jq '[.data.me.posts.nodes[] | {id, title, url, views, reactions: .reactionCount, responses: .responseCount}]'查看单篇文章的完整内容+统计数据:
bash
gql 'query GetPost($id: ObjectId!) { post(id: $id) { title url views reactionCount responseCount content { markdown } } }' \
"$(jq -n --arg id "POST_ID" '{id:$id}')" | jq '.data.post | {title, url, views, reactions: .reactionCount}'Gotchas
注意事项
- No prefix — the
Bearerheader carries the raw token.Authorization - is mandatory for publishing/drafting — never guess it, read it from the
publicationIdquery.me - is required on
tags— supply at least onepublishPost; slug must be lowercase with hyphens (e.g.{name, slug}).machine-learning - on HTTP 200 — GraphQL reports failures in the
errorsarray, not via status codes; always surface them.errors - Idempotency — re-running creates a new post each time; to change an existing one use
publishPostwith itsupdatePost.id
- 不要加前缀 —
Bearer请求头携带原始令牌即可。Authorization - 是发布/保存草稿的必填项 — 切勿猜测,务必从
publicationId查询中获取。me - 必须包含
publishPost— 至少提供一个tags;slug必须是小写并使用连字符(例如{name, slug})。machine-learning - HTTP 200状态码下仍可能存在— GraphQL通过
errors数组报告错误,而非状态码;务必展示这些错误信息。errors - 幂等性 — 重复运行会每次创建一篇新文章;要修改现有文章,请使用
publishPost并传入文章updatePost。id
Record the output
记录输出结果
After you successfully publish and obtain the live result URL, call the built-in
tool ONCE so the user can track this deliverable in My Outputs:
publish_artifactpublish_artifact(kind="article", channel="hashnode", title="<title>", url="<the REAL returned URL>", status="delivered")Use the real returned URL — never fabricate one. Call it once per published item,
only after delivery is confirmed; skip it (or use ) if publishing failed.
See .
status="failed"_shared/artifacts.md成功发布并获取文章的实际URL后,调用内置的工具一次,以便用户在我的输出中跟踪此交付成果:
publish_artifactpublish_artifact(kind="article", channel="hashnode", title="<title>", url="<the REAL returned URL>", status="delivered")使用实际返回的URL——切勿伪造。每发布一个项目调用一次,仅在确认交付成功后调用;如果发布失败,则跳过(或使用)。详情请见。
status="failed"_shared/artifacts.md