用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/kemalcr/kemal --skill kemal-json命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Use when building, reviewing, debugging, testing, securing, or deploying web applications and HTTP APIs with the Kemal framework for Crystal. Covers Kemal routing, params, context, routers, filters, middleware, ECR, WebSockets, SSE, uploads, configuration, testing, and production concerns.
User authentication and session management in Kemal, following established project patterns.
Core Kemal development (routing verbs, parameters, modular router, version gates, response helpers).
正在显示 SKILL.md
| name | kemal-json |
| description | Building JSON APIs with Kemal using built-in response helpers and established project patterns. |
| license | MIT |
This skill provides expert guidance on building robust JSON APIs with Kemal, establishing the canonical patterns for JSON response helpers and strictly following patterns from kemal-by-example/json-api.
env.json and env.status response helpers (symbol or integer statuses): since Kemal 1.10.400 Bad Request on Kemal master; earlier releases return 500.Dependencies: Always require "json".
Built-in Context Response Helpers (Kemal 1.10+): Use Kemal's built-in env.json and status helpers for API responses:
# Basic JSON response (sets Content-Type to application/json; charset=utf-8 automatically)
get "/api/users" do |env|
env.json({users: %w[alice bob]})
end
# Symbol or integer HTTP status code with JSON:
post "/api/users" do |env|
env.status(:created).json({id: 1, name: "Alice"})
end
# Early halt with JSON:
get "/api/protected" do |env|
halt env.status(:unauthorized).json({error: "Unauthorized"}) unless authenticated?(env)
end
Project JsonResponse Helpers (Custom Pattern): When using standard project helpers for responses (found in JsonApi::JsonResponse):
module JsonApi
module JsonResponse
extend self
def json(env : HTTP::Server::Context, status : Int32, payload : String)
env.response.status_code = status
env.response.content_type = "application/json; charset=utf-8"
payload
end
def error(env : HTTP::Server::Context, status : Int32, message : String)
json(env, status, {"error" => message}.to_json)
end
end
end
Safe JSON Body Parsing: Use env.params.raw_body or read_json_object(env) to safely parse JSON bodies and handle exceptions:
private def read_json_object(env : HTTP::Server::Context) : Hash(String, JSON::Any)?
raw = env.params.raw_body
return nil if raw.strip.empty?
parsed = JSON.parse(raw)
parsed.as_h?
rescue JSON::ParseException
nil
end
Serialization: Models should provide a to_h method. Use model.to_h or model.to_h.to_json for responses.
require "json"
require "../helpers/json_response"
require "../models/note"
private def read_json_object(env : HTTP::Server::Context) : Hash(String, JSON::Any)?
raw = env.params.raw_body
return nil if raw.strip.empty?
parsed = JSON.parse(raw)
parsed.as_h?
rescue JSON::ParseException
nil
end
private def note_id(env : HTTP::Server::Context) : Int64?
env.params.url["id"]?.try(&.to_i64?)
end
private def string_field(h : Hash(String, JSON::Any), key : String) : String?
h[key]?.try(&.as_s?)
end
get "/api/notes" do |env|
list = Note.all.map(&.to_h)
env.json({"notes" => list})
end
get "/api/notes/:id" do |env|
id = note_id(env)
unless id
halt env.status(:bad_request).json({"error" => "invalid id"})
end
note = Note.find(id)
if note
env.json(note.to_h)
else
env.status(:not_found).json({"error" => "note not found"})
end
end
post "/api/notes" do |env|
obj = read_json_object(env)
unless obj
halt env.status(:bad_request).json({"error" => "expected JSON object body"})
end
title = string_field(obj, "title").try(&.strip) || ""
if title.empty?
halt env.status(:unprocessable_entity).json({"error" => "title is required"})
end
body = string_field(obj, "body").try(&.strip) || ""
new_id = Note.create(title, body)
note = Note.find(new_id)
if note
env.status(:created).json(note.to_h)
else
env.status(:internal_server_error).json({"error" => "failed to load created note"})
end
end
delete "/api/notes/:id" do |env|
id = note_id(env)
unless id
halt env.status(:bad_request).json({"error" => "invalid id"})
end
note = Note.find(id)
unless note
halt env.status(:not_found).json({"error" => "note not found"})
end
note.delete
env.status(:no_content)
end
env.json and env.status(...) for idiomatic, chainable response handling.error key for failure states.obj[key]?.try(&.as_s?) or similar safe accessors for fields in parsed JSON hashes.:ok, :created, :no_content, :bad_request, :unauthorized, :not_found, :unprocessable_entity.