원클릭으로
add-http-api
Guide for adding new JSON-RPC HTTP API methods in Neptune. Use when asked to add a new API endpoint, RPC method, or HTTP handler.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Guide for adding new JSON-RPC HTTP API methods in Neptune. Use when asked to add a new API endpoint, RPC method, or HTTP handler.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | add-http-api |
| description | Guide for adding new JSON-RPC HTTP API methods in Neptune. Use when asked to add a new API endpoint, RPC method, or HTTP handler. |
Neptune uses a custom JSON-RPC 2.0 framework with auto-generated OpenAPI specs. All API methods are registered via usecase.Interactor + jsonrpc.Handler.Add().
Each API method is a single Go file in internal/web/ (package web) with three parts:
json:"", description:"", required:"true", and optionally validate:"required" for the validator.json:"" and optionally required:"true".usecase.Interactor, calls u.SetName("method.name") and h.Add(u).internal/web/<feature>.gopackage web
import (
"context"
"github.com/swaggest/usecase"
"neptune/internal/client"
"neptune/internal/web/jsonrpc"
)
type myMethodRequest struct {
ParamA string `description:"description of param_a" json:"param_a" required:"true"`
ParamB int64 `description:"description of param_b" json:"param_b"`
}
type myMethodResponse struct {
Result string `json:"result"`
}
func myMethod(h *jsonrpc.Handler, c *core.Client) {
u := usecase.NewInteractor(
func(ctx context.Context, req *myMethodRequest, res *myMethodResponse) error {
// implementation
return nil
},
)
u.SetName("my.method")
h.Add(u)
}
internal/web/web.goIn the New() function, add a call to your registration function alongside the existing ones:
myMethod(h, c)
That's it — no separate route definition, no middleware wiring. All JSON-RPC methods go through the single POST /json_rpc handler.
usecase.NewInteractor: For request structs, always use *MyRequest (pointer). Response structs can be value or pointer — existing code uses both *X and X.AddTorrentRequest; internal methods use unexported: addTagsRequest.description + json + required tags are needed for OpenAPI generation. The description tag populates the OpenAPI spec.go-playground/validator auto-validates request structs. Use validate:"required" for additional validation beyond required:"true".type myResponse struct{} — the JSON-RPC framework handles empty objects correctly.Info hash fields must be 40 hex characters (sha1.Size*2 == 40). The canonical pattern:
if len(req.InfoHash) != sha1.Size*2 {
return errInvalidInfoHash
}
raw, err := hex.DecodeString(req.InfoHash)
if err != nil {
return errInvalidInfoHash
}
hash := metainfo.Hash(raw)
A shared helper checkInfoHash() exists in internal/web/torrent_speed_limit.go — prefer using it for new methods.
Use CodeError(code int, err error) from internal/web/error.go to return errors with custom numeric codes:
if err != nil {
return CodeError(1, errgo.Wrap(err, "description of what failed"))
}
The JSON-RPC handler (internal/web/jsonrpc/handler.go) checks for the ErrWithAppCode interface. When present, the error code replaces the default -32603 (InternalError) and the error message is sent verbatim.
Error code conventions by existing methods:
| Code | Meaning |
|---|---|
| 1 | Invalid parameter (bad info_hash, invalid limit value) |
| 2 | Operation failed (torrent parse error, get download error, schedule move error) |
| 4 | Validation rejected (piece length too big, etc.) |
| 5 | Specific operation failure (add torrent failure) |
Always wrap errors with trim21/errgo:
return errgo.Wrap(err, "failed to do something")
"scope.action" or "scope.sub_scope.action"torrent.add, torrent.start, torrent.set_file_priority, client.set_upload_limit, transfer_summary, system.pingSetName() must be called before h.Add(u). The name string becomes both the JSON-RPC method field and the OpenAPI operationId.h.Add(u) WorksHandler.Add() in internal/web/jsonrpc/handler.go:
usecase.HasName interface (panics if missing).api-key security.The ServeHTTP handler then:
method fieldu.Interact(ctx, input, output)All JSON-RPC methods are behind a single auth middleware in web.go:
r.With(middleware.NoCache, auth).Handle("POST /json_rpc", h)
The auth check compares the Authorization header against the configured token. Failed auth returns a JSON-RPC error with CodeInvalidRequest (-32600).
No per-method auth handling is needed — it's handled uniformly at the route level.
Standard imports for a new API file:
import (
"context"
"crypto/sha1"
"encoding/hex"
"github.com/swaggest/usecase"
"github.com/trim21/errgo"
"neptune/internal/client"
"neptune/internal/metainfo"
"neptune/internal/web/jsonrpc"
)
.go file in internal/web/ with request + response structs + registration functionjson, description, required tagsjson tagssha1.Size*2 (40 chars) + hex.DecodeStringerrgo.Wrap + CodeError for application error codesu.SetName("scope.method_name") with a unique, descriptive nameweb.go:New()POST /json_rpc handles it automatically