From 9b82f6c93a41ca8f91fba779ddf96bf03616449c Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Mon, 6 Apr 2020 21:09:01 +0200 Subject: [PATCH 1/4] Improve generation of HTTP API reference * Document how to send the multiparts for /add * Bring markdown geneartion in line with ipfs-docs-v2 * Ignore client-side options * Set curl -X POST * Do not list args of type File in arguments * Improve some formatting This still leaves things at 0.4.22 so that then we can get a clean diff of changes for 0.4.23 and eventually for 0.5.0. Fixes #25 Fixes #4 --- endpoints.go | 18 +++++++ go.mod | 2 +- go.sum | 17 ++++++ markdown.go | 146 ++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 141 insertions(+), 42 deletions(-) diff --git a/endpoints.go b/endpoints.go index c944eb5..cfad1fc 100644 --- a/endpoints.go +++ b/endpoints.go @@ -23,6 +23,17 @@ var JsondocGlossary = jsondoc.NewGlossary(). WithSchema(new(peerstore.PeerInfo), jsondoc.Object{"ID": "peer-id", "Addrs": []string{""}}) +var clientOpts = map[string]struct{}{ + cmds.EncLong: struct{}{}, + cmds.RecLong: struct{}{}, + cmds.TimeoutOpt: struct{}{}, + cmds.DerefLong: struct{}{}, + cmds.StdinName: struct{}{}, + cmds.Hidden: struct{}{}, + cmds.Ignore: struct{}{}, + cmds.IgnoreRules: struct{}{}, +} + // A map of single endpoints to be skipped (subcommands are processed though). var IgnoreEndpoints = map[string]bool{} @@ -44,6 +55,7 @@ type Endpoint struct { // Argument defines an IPFS RPC API endpoint argument. type Argument struct { + Endpoint string Name string Description string Type string @@ -84,6 +96,7 @@ func Endpoints(name string, cmd *cmds.Command) (endpoints []*Endpoint) { argType = "file" } arguments = append(arguments, &Argument{ + Endpoint: name, Name: arg.Name, Type: argType, Required: arg.Required, @@ -92,6 +105,11 @@ func Endpoints(name string, cmd *cmds.Command) (endpoints []*Endpoint) { } for _, opt := range cmd.Options { + // skip client-side options + if _, ok := clientOpts[opt.Names()[0]]; ok { + continue + } + def := fmt.Sprint(opt.Default()) if def == "" { def = "" diff --git a/go.mod b/go.mod index e75000e..b1e61df 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/Stebalien/go-json-doc v0.0.2 github.com/ipfs/go-cid v0.0.2 github.com/ipfs/go-ipfs v0.4.22 - github.com/ipfs/go-ipfs-cmds v0.0.8 + github.com/ipfs/go-ipfs-cmds v0.2.2 github.com/libp2p/go-libp2p-peer v0.1.1 github.com/libp2p/go-libp2p-peerstore v0.0.6 github.com/multiformats/go-multiaddr v0.0.4 diff --git a/go.sum b/go.sum index 01f9da9..27634e4 100644 --- a/go.sum +++ b/go.sum @@ -50,6 +50,8 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a h1:U0BbGfKnviqVBJQB4etvm+mKx53KfkumNLBt6YeF/0Q= github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -204,6 +206,8 @@ github.com/ipfs/go-ipfs-chunker v0.0.1 h1:cHUUxKFQ99pozdahi+uSC/3Y6HeRpi9oTeUHbE github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= github.com/ipfs/go-ipfs-cmds v0.0.8 h1:ZMo0ZeQOr10ZKY4yxYA3lRHUbnF/ZYcV9cpU0IrlGFI= github.com/ipfs/go-ipfs-cmds v0.0.8/go.mod h1:TiK4e7/V31tuEb8YWDF8lN3qrnDH+BS7ZqWIeYJlAs8= +github.com/ipfs/go-ipfs-cmds v0.2.2 h1:F2pro/Q3ifRUsdxEKIS8cg8lO4R6WiwAyERiaG8I9no= +github.com/ipfs/go-ipfs-cmds v0.2.2/go.mod h1:kqlUrp6m2ceoaJe40cXpADCi5aS6NKRn0NIeuLp5CeM= github.com/ipfs/go-ipfs-config v0.0.1/go.mod h1:KDbHjNyg4e6LLQSQpkgQMBz6Jf4LXiWAcmnkcwmH0DU= github.com/ipfs/go-ipfs-config v0.0.3 h1:Ep4tRdP1iVK76BgOprD9B/qtOEdpno+1Xb57BqydgGk= github.com/ipfs/go-ipfs-config v0.0.3/go.mod h1:KDbHjNyg4e6LLQSQpkgQMBz6Jf4LXiWAcmnkcwmH0DU= @@ -219,6 +223,8 @@ github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAz github.com/ipfs/go-ipfs-files v0.0.2/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.3 h1:ME+QnC3uOyla1ciRPezDW0ynQYK2ikOh9OCKAEg4uUA= github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg= +github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= github.com/ipfs/go-ipfs-flags v0.0.1/go.mod h1:RnXBb9WV53GSfTrSDVK61NLTFKvWc60n+K9EgCDh+rA= github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= @@ -240,6 +246,10 @@ github.com/ipfs/go-ipns v0.0.1 h1:5vX0+ehF55YWxE8Pmf4eB8szcP+fh24AXnvCkOmSLCc= github.com/ipfs/go-ipns v0.0.1/go.mod h1:HOiAXgGiH0wCSwsFM1IKdOy6YGT4iZafcsUKni703/g= github.com/ipfs/go-log v0.0.1 h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-log v1.0.3 h1:Gg7SUYSZ7BrqaKMwM+hRgcAkKv4QLfzP4XPQt5Sx/OI= +github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= +github.com/ipfs/go-log/v2 v2.0.3 h1:Q2gXcBoCALyLN/pUQlz1qgu0x3uFV6FzP9oXhpfyJpc= +github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-merkledag v0.0.3 h1:A5DlOMzqTRDVmdgkf3dzCKCFmVWH4Zqwb0cbYXUs+Ro= github.com/ipfs/go-merkledag v0.0.3/go.mod h1:Oc5kIXLHokkE1hWGMBHw+oxehkAaTOqtEb7Zbh6BhLA= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= @@ -560,6 +570,7 @@ github.com/prometheus/procfs v0.0.0-20190519111021-9935e8e0588d/go.mod h1:TjEm7z github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= @@ -597,6 +608,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g= @@ -651,6 +664,8 @@ go.uber.org/goleak v0.10.0 h1:G3eWbSNIskeRqtsN/1uI5B+eP73y3JUuBsv9AZjehb4= go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go4.org v0.0.0-20190218023631-ce4c26f7be8e/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20190313082347-94abd6928b1d h1:JkRdGP3zvTtTbabWSAC6n67ka30y7gOzWAah4XYJSfw= go4.org v0.0.0-20190313082347-94abd6928b1d/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= @@ -666,6 +681,8 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d h1:2+ZP7EfsZV7Vvmx3TIqSlSzATMkTAKqM14YGFPoSKjI= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= diff --git a/markdown.go b/markdown.go index eeb6265..b6369ee 100644 --- a/markdown.go +++ b/markdown.go @@ -3,6 +3,7 @@ package docs import ( "bytes" "fmt" + "html" "regexp" "strings" "time" @@ -16,17 +17,17 @@ type MarkdownFormatter struct{} func (md *MarkdownFormatter) GenerateIntro() string { buf := new(bytes.Buffer) fmt.Fprintf(buf, `--- -title: "HTTP API" -weight: 20 -menu: - reference: - parent: api +title: HTTP API +legacyUrl: https://docs.ipfs.io/reference/api/http/ +description: HTTP API reference for IPFS, the InterPlanetary File System. --- +# HTTP API reference + -Generated on %s, from go-ipfs v%s. +_Generated on %s, from go-ipfs v%s._ When an IPFS node is running as a daemon, it exposes an HTTP API that allows you to control the node and run the same commands you can from the command @@ -36,22 +37,21 @@ In many cases, using this API this is preferable to embedding IPFS directly in your program — it allows you to maintain peer connections that are longer lived than your app and you can keep a single IPFS node running instead of several if your app can be launched multiple times. In fact, the `+"`ipfs`"+` -CLI commands use this API when operating in [online mode]({{< relref -"usage.md#taking-your-node-online" >}}). +CLI commands use this API when operating in online mode. - +::: tip +This document was autogenerated from go-ipfs. For issues and support, check +out the [ipfs-http-api-docs](https://github.com/ipfs/ipfs-http-api-docs) +repository on GitHub. +::: -## Getting Started +## Getting started -### Alignment with CLI Commands +### Alignment with CLI commands The HTTP API under `+"`/api/v0/`"+` is an RPC-style API over HTTP, not a REST API. -[Every command]({{< relref "cli.md" >}}) usable from the CLI is also available through +[Every command](/reference/cli/) usable from the CLI is also available through the HTTP API. For example: `+"```sh"+ ` @@ -60,7 +60,7 @@ the HTTP API. For example: /ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx /ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z -> curl http://127.0.0.1:5001/api/v0/swarm/peers +> curl -X POST http://127.0.0.1:5001/api/v0/swarm/peers { "Strings": [ "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", @@ -68,15 +68,14 @@ the HTTP API. For example: "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", ] } -`+ - "```"+` +`+"```"+` ### Arguments Arguments are added through the special query string key "arg": `+"```"+` -> curl "http://127.0.0.1:5001/api/v0/swarm/disconnect?arg=/ip4/54.93.113.247/tcp/48131/ipfs/QmUDS3nsBD1X4XK5Jo836fed7SErTyTuQzRqWaiQAyBYMP" +> curl -X POST "http://127.0.0.1:5001/api/v0/swarm/disconnect?arg=/ip4/54.93.113.247/tcp/48131/ipfs/QmUDS3nsBD1X4XK5Jo836fed7SErTyTuQzRqWaiQAyBYMP" { "Strings": [ "disconnect QmUDS3nsBD1X4XK5Jo836fed7SErTyTuQzRqWaiQAyBYMP success", @@ -92,7 +91,7 @@ Flags are added through the query string. For example, the %s flag is the %s query parameter below: `+"```"+` -> curl "http://127.0.0.1:5001/api/v0/object/get?arg=QmaaqrHyAQm7gALkRW8DcfGX3u8q9rWKnxEMmf7m9z515w&encoding=json" +> curl -X POST "http://127.0.0.1:5001/api/v0/object/get?arg=QmaaqrHyAQm7gALkRW8DcfGX3u8q9rWKnxEMmf7m9z515w&encoding=json" { "Links": [ { @@ -110,18 +109,31 @@ flag is the %s query parameter below: } `+"```"+` -### HTTP Status Codes +::: tip +Some arguments may belong only to the CLI but appear here too. These usually +belong to client-side processing of input, particularly in the `+"`add`"+` command. +::: + + +## HTTP status codes Status codes used at the RPC layer are simple: -* `+"`500`"+` - RPC endpoint returned an error -* `+"`404`"+` - RPC endpoint doesn't exist -* `+"`400`"+` - Malformed RPC, argument type error, etc -* `+"`403`"+` - RPC call forbidden +- `+"`500`"+` - RPC endpoint returned an error +- `+"`400`"+` - Malformed RPC, argument type error, etc +- `+"`403`"+` - RPC call forbidden +- `+"`404`"+` - RPC endpoint doesn't exist +- `+"`405`"+` - HTTP Method Not Allowed -In other words, `+"`500`"+` means that the function _does_ exist, it just failed internally for some reason. To know that reason, you have to look at the "application layer" error (commands lib error). +In other words, `+"`500`"+` means that the function _does_ exist, it just +failed internally for some reason. To know that reason, you have to look at +the "application layer" error (usually returned with the body of the command). -## HTTP Commands +A `+"`405`"+`error may mean that you are using the wrong HTTP method +(i.e. GET instead of POST), or that you are not allowed to call that method +(i.e. due to CORS restrictions when making a request from a browser). + +## HTTP commands `, time.Now().Format("2006-01-02"), IPFSVersion(), @@ -148,18 +160,18 @@ func (md *MarkdownFormatter) GenerateIndex(endps []*Endpoint) string { func (md *MarkdownFormatter) GenerateEndpointBlock(endp *Endpoint) string { buf := new(bytes.Buffer) fmt.Fprintf(buf, ` -### %s +## %s %s -`, endp.Name, endp.Description) +`, endp.Name, html.EscapeString(endp.Description)) return buf.String() } func (md *MarkdownFormatter) GenerateArgumentsBlock(args []*Argument, opts []*Argument) string { buf := new(bytes.Buffer) - fmt.Fprintf(buf, "#### Arguments\n\n") + fmt.Fprintf(buf, "### Arguments\n\n") if len(args)+len(opts) == 0 { fmt.Fprintf(buf, "This endpoint takes no arguments.\n") @@ -176,16 +188,27 @@ func (md *MarkdownFormatter) GenerateArgumentsBlock(args []*Argument, opts []*Ar return buf.String() } +// Removes the "Default:..." part in the descriptions. +var fixDesc, _ = regexp.Compile(" Default: [a-zA-z0-9-_]+ ?\\.") + func genArgument(arg *Argument, aliasToArg bool) string { + // These get handled by GenerateBodyBlock + if arg.Type == "file" { + return "\n" + } + buf := new(bytes.Buffer) alias := arg.Name if aliasToArg { alias = "arg" } - fixDesc, _ := regexp.Compile(" Default: [a-zA-z0-9-_]+ ?\\.") - fmt.Fprintf(buf, " - `%s` [%s]: %s", alias, arg.Type, fixDesc.ReplaceAll([]byte(arg.Description), []byte(""))) + + fixedDescription := string(fixDesc.ReplaceAll([]byte(arg.Description), []byte(""))) + fixedDescription = html.EscapeString(fixedDescription) + + fmt.Fprintf(buf, "- `%s` [%s]: %s", alias, arg.Type, fixedDescription) if len(arg.Default) > 0 { - fmt.Fprintf(buf, ` Default: "%s".`, arg.Default) + fmt.Fprintf(buf, " Default: `%s`.", arg.Default) } if arg.Required { fmt.Fprintf(buf, ` Required: **yes**.`) @@ -208,11 +231,52 @@ func (md *MarkdownFormatter) GenerateBodyBlock(args []*Argument) string { if bodyArg != nil { buf := new(bytes.Buffer) fmt.Fprintf(buf, ` -#### Request Body +### Request Body -Argument "%s" is of file type. This endpoint expects a file in the body of the request as 'multipart/form-data'. +Argument `+"`%s`"+` is of file type. This endpoint expects one or several files +(depending on the command) in the body of the request as +'multipart/form-data'. `, bodyArg.Name) + + // Special documentation for /add + if bodyArg.Endpoint == "/api/v0/add" { + fmt.Fprintln(buf, html.EscapeString(` + +The `+"`add`"+` command not only allow adding files, but also uploading +directories and complex hierarchies. + +This happens as follows: Every part in the multipart request is a *directory* +or a *file* to be added to IPFS. + +Directory parts have a special content type `+"`application/x-directory`"+`. +These parts do not carry any data. The part headers look as follows: + +`+"```"+` +Content-Disposition: form-data; name="file"; filename="folderName" +Content-Type: application/x-directory +`+"```"+` + +File parts carry the file payload after the following headers: + +`+"```"+` +Abspath: /absolute/path/to/file.txt +Content-Disposition: form-data; name="file"; filename="folderName%2Ffile.txt" +Content-Type: application/octet-stream + + +`+"```"+` + +The above file includes its path in the "folderName/file.txt" hierarchy and +IPFS will therefore be able to add it inside "folderName". The parts declaring +the directories must be sent before the parts of their contents (ipfs +does it with a depth-first traversal of the directory tree). + +The `+"`Abspath`"+` header is included for filestore/urlstore features that +are enabled with the `+"`nocopy`"+` option and it can be set to the location +of the file in the filesystem (within the IPFS root), or to its full web URL. +`)) + } return buf.String() } return "" @@ -221,7 +285,7 @@ Argument "%s" is of file type. This endpoint expects a file in the body of the r func (md *MarkdownFormatter) GenerateResponseBlock(response string) string { buf := new(bytes.Buffer) fmt.Fprintf(buf, ` -#### Response +### Response On success, the call to this endpoint will return with 200 and the following body: @@ -234,9 +298,9 @@ On success, the call to this endpoint will return with 200 and the following bod func (md *MarkdownFormatter) GenerateExampleBlock(endp *Endpoint) string { buf := new(bytes.Buffer) - fmt.Fprintf(buf, "#### cURL Example\n\n") + fmt.Fprintf(buf, "### cURL Example\n\n") fmt.Fprintf(buf, "`") - fmt.Fprintf(buf, "curl ") + fmt.Fprintf(buf, "curl -X POST ") // Assemble arguments which are not of type file var queryargs []string @@ -269,13 +333,13 @@ func (md *MarkdownFormatter) GenerateExampleBlock(endp *Endpoint) string { fmt.Fprintf(buf, "-F file=@myfile ") } - fmt.Fprintf(buf, "\"http://localhost:5001%s", endp.Name) + fmt.Fprintf(buf, "\"http://127.0.0.1:5001%s", endp.Name) if len(queryargs) > 0 { fmt.Fprintf(buf, "?%s\"", strings.Join(queryargs, "&")) } else { fmt.Fprintf(buf, "\"") } - fmt.Fprintf(buf, "`\n\n***\n") + fmt.Fprintf(buf, "`\n\n---\n") return buf.String() } From 597306568b7446e2dc2c6c02d613c951990f631f Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Mon, 6 Apr 2020 21:16:03 +0200 Subject: [PATCH 2/4] travis: install: true --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5882806..884b7b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ env: go: - 1.13.x -install: false +install: true script: - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) From 9138e00829fa6828c844bc4a959c17f693676db6 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 7 Apr 2020 00:16:21 +0200 Subject: [PATCH 3/4] Address reviews to include the right flags and be more accurate in descriptions Co-Authored-By: Steven Allen --- endpoints.go | 2 -- markdown.go | 19 ++++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/endpoints.go b/endpoints.go index cfad1fc..057acb1 100644 --- a/endpoints.go +++ b/endpoints.go @@ -24,9 +24,7 @@ var JsondocGlossary = jsondoc.NewGlossary(). jsondoc.Object{"ID": "peer-id", "Addrs": []string{""}}) var clientOpts = map[string]struct{}{ - cmds.EncLong: struct{}{}, cmds.RecLong: struct{}{}, - cmds.TimeoutOpt: struct{}{}, cmds.DerefLong: struct{}{}, cmds.StdinName: struct{}{}, cmds.Hidden: struct{}{}, diff --git a/markdown.go b/markdown.go index b6369ee..5a8462c 100644 --- a/markdown.go +++ b/markdown.go @@ -111,7 +111,8 @@ flag is the %s query parameter below: ::: tip Some arguments may belong only to the CLI but appear here too. These usually -belong to client-side processing of input, particularly in the `+"`add`"+` command. +belong to client-side processing of input, particularly in the `+"`add`"+` +command. ::: @@ -119,15 +120,18 @@ belong to client-side processing of input, particularly in the `+"`add`"+` comma Status codes used at the RPC layer are simple: +- `+"`200`"+` - The request was processed or is being processed (streaming) - `+"`500`"+` - RPC endpoint returned an error - `+"`400`"+` - Malformed RPC, argument type error, etc - `+"`403`"+` - RPC call forbidden - `+"`404`"+` - RPC endpoint doesn't exist - `+"`405`"+` - HTTP Method Not Allowed -In other words, `+"`500`"+` means that the function _does_ exist, it just -failed internally for some reason. To know that reason, you have to look at -the "application layer" error (usually returned with the body of the command). +Status code `+"`500`"+` means that the function _does_ exist, it just failed +internally for some reason. To know that reason, you have to look at the +"application layer" error (usually returned with the body of the command). In +the case of streaming endpoints, they always return 200 before starting to +stream the response. Any errors are included as Trailer response headers. A `+"`405`"+`error may mean that you are using the wrong HTTP method (i.e. GET instead of POST), or that you are not allowed to call that method @@ -243,7 +247,7 @@ Argument `+"`%s`"+` is of file type. This endpoint expects one or several files if bodyArg.Endpoint == "/api/v0/add" { fmt.Fprintln(buf, html.EscapeString(` -The `+"`add`"+` command not only allow adding files, but also uploading +The `+"`add`"+` command not only allows adding files, but also uploading directories and complex hierarchies. This happens as follows: Every part in the multipart request is a *directory* @@ -269,8 +273,9 @@ Content-Type: application/octet-stream The above file includes its path in the "folderName/file.txt" hierarchy and IPFS will therefore be able to add it inside "folderName". The parts declaring -the directories must be sent before the parts of their contents (ipfs -does it with a depth-first traversal of the directory tree). +the directories are optional when they have files inside and will be inferred +from the filenames. In any case, a depth-first traversal of the directory tree +is recommended to order the different parts making the request. The `+"`Abspath`"+` header is included for filestore/urlstore features that are enabled with the `+"`nocopy`"+` option and it can be set to the location From 4c9b471c83541018c5c231f89d6af8b53453bea3 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 7 Apr 2020 16:10:59 +0200 Subject: [PATCH 4/4] Improve status code descriptions Co-Authored-By: Steven Allen --- markdown.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/markdown.go b/markdown.go index 5a8462c..25f8785 100644 --- a/markdown.go +++ b/markdown.go @@ -127,11 +127,16 @@ Status codes used at the RPC layer are simple: - `+"`404`"+` - RPC endpoint doesn't exist - `+"`405`"+` - HTTP Method Not Allowed -Status code `+"`500`"+` means that the function _does_ exist, it just failed -internally for some reason. To know that reason, you have to look at the -"application layer" error (usually returned with the body of the command). In -the case of streaming endpoints, they always return 200 before starting to -stream the response. Any errors are included as Trailer response headers. +Status code `+"`500`"+` means that the function _does_ exist, but IPFS was not +able to fulfil the request because of an error. To know that reason, you have +to look at the the error message that is usually returned with the body of the +response (if no error, check the daemon logs). + +Streaming endpoints fail as above, unless they have started streaming. That +means they will have sent a `+"`200`"+` status code already. If an error +happens during the stream, it will be included in a Trailer response header +(some endpoints may additionally include an error in the last streamed +object). A `+"`405`"+`error may mean that you are using the wrong HTTP method (i.e. GET instead of POST), or that you are not allowed to call that method