Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slashes matter in calls? #346

Closed
ghost opened this issue Feb 17, 2014 · 2 comments
Closed

Slashes matter in calls? #346

ghost opened this issue Feb 17, 2014 · 2 comments

Comments

@ghost
Copy link

ghost commented Feb 17, 2014

I moved this issue over from lostisland/sawyer as it turns out it is a Faraday issue.


Get for instance this Pry session:

~ pry
[1] pry(main)> require 'faraday'
=> true
[2] pry(main)> conn = Faraday.new('http://eval.so/api')
=> #<Faraday::Connection:0x007f95ba71a488
 @builder=
  #<Faraday::RackBuilder:0x007f95ba71a0a0
   @handlers=[Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp]>,
 @default_parallel_manager=nil,
 @headers={"User-Agent"=>"Faraday v0.9.0"},
 @options=
  #<struct Faraday::RequestOptions
   params_encoder=nil,
   proxy=nil,
   bind=nil,
   timeout=nil,
   open_timeout=nil,
   boundary=nil,
   oauth=nil>,
 @parallel_manager=nil,
 @params={},
 @proxy=nil,
 @ssl=
  #<struct Faraday::SSLOptions
   verify=nil,
   ca_file=nil,
   ca_path=nil,
   verify_mode=nil,
   cert_store=nil,
   client_cert=nil,
   client_key=nil,
   certificate=nil,
   private_key=nil,
   verify_depth=nil,
   version=nil>,
 @url_prefix=#<URI::HTTP:0x007f95bc3a98b0 URL:http://eval.so/api>>
[3] pry(main)> conn.get('languages')
=> #<Faraday::Response:0x007f95bc359f90
 @env=
  #<struct Faraday::Env
   method=:get,
   body=
    "{\"csharp\":{\"display_name\":\"C#\"},\"rust\":{\"display_name\":\"Rust 0.7
   url=#<URI::HTTP:0x007f95bc368540 URL:http://eval.so/api/languages>,
   request=
    #<struct Faraday::RequestOptions
     params_encoder=nil,
     proxy=nil,
     bind=nil,
     timeout=nil,
     open_timeout=nil,
     boundary=nil,
     oauth=nil>,
   request_headers={"User-Agent"=>"Faraday v0.9.0"},
   ssl=
    #<struct Faraday::SSLOptions
     verify=nil,
     ca_file=nil,
     ca_path=nil,
     verify_mode=nil,
     cert_store=nil,
     client_cert=nil,
     client_key=nil,
     certificate=nil,
     private_key=nil,
     verify_depth=nil,
     version=nil>,
   parallel_manager=nil,
   params=nil,
   response=nil,
   response_headers=
    {"server"=>"nginx/1.4.3",
     "date"=>"Mon, 17 Feb 2014 14:50:42 GMT",
     "content-type"=>"application/json; charset=utf-8",
     "transfer-encoding"=>"chunked",
     "connection"=>"close",
     "access-control-allow-origin"=>"*"},
   status=200>,
 @on_complete_callbacks=[]>
[4] pry(main)> conn.get('/languages')
=> #<Faraday::Response:0x007f95bc2e8408
 @env=
  #<struct Faraday::Env
   method=:get,
   body=
    "\n\n<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<title>Action not found</title>\
   url=#<URI::HTTP:0x007f95bc2f2408 URL:http://eval.so/languages>,
   request=
    #<struct Faraday::RequestOptions
     params_encoder=nil,
     proxy=nil,
     bind=nil,
     timeout=nil,
     open_timeout=nil,
     boundary=nil,
     oauth=nil>,
   request_headers={"User-Agent"=>"Faraday v0.9.0"},
   ssl=
    #<struct Faraday::SSLOptions
     verify=nil,
     ca_file=nil,
     ca_path=nil,
     verify_mode=nil,
     cert_store=nil,
     client_cert=nil,
     client_key=nil,
     certificate=nil,
     private_key=nil,
     verify_depth=nil,
     version=nil>,
   parallel_manager=nil,
   params=nil,
   response=nil,
   response_headers=
    {"server"=>"nginx/1.4.3",
     "date"=>"Mon, 17 Feb 2014 14:50:52 GMT",
     "content-type"=>"text/html; charset=utf-8",
     "transfer-encoding"=>"chunked",
     "connection"=>"close"},
   status=404>,
 @on_complete_callbacks=[]>

It seems like calling GET on the path languages is successful (200), but /languages fails (404). Is this a bug or a feature? Wouldn't it make sense for them to be optionally included (or required based on the API endpoint - whether it has a / at the end or not)?

This is the same example but using Sawyer instead:

~  pry
[1] pry(main)> require 'sawyer'
=> true
[2] pry(main)> agent = Sawyer::Agent.new('http://eval.so/api')
=> <Sawyer::Agent http://eval.so/api>
[3] pry(main)> agent.call :get, 'languages'
=> #<Sawyer::Response: 200 @rels={} @data=#<Sawyer::Resource:0x007ffa460e6148 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:csharp, :rust, :clojure, :python2, :idris, :chickenscheme, :jruby18, :haskell, :perl, :smalltalk, :python3, :java, :factor, :"c++", :go, :jruby19, :php, :lua, :scala, :fsharp, :io, :c, :lolcode, :"sml-mlton", :perl6, :ruby, :elixir, :vbnet, :bash}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460e6148>>, @attrs={:csharp=>#<Sawyer::Resource:0x007ffa460e5f90 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460e5f90>>, @attrs={:display_name=>"C#"}>, :rust=>#<Sawyer::Resource:0x007ffa460e59a0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460e59a0>>, @attrs={:display_name=>"Rust 0.7"}>, :clojure=>#<Sawyer::Resource:0x007ffa460e5568 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460e5568>>, @attrs={:display_name=>"Clojure"}>, :python2=>#<Sawyer::Resource:0x007ffa460e5130 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460e5130>>, @attrs={:display_name=>"Python 2"}>, :idris=>#<Sawyer::Resource:0x007ffa460e4cf8 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460e4cf8>>, @attrs={:display_name=>"Idris"}>, :chickenscheme=>#<Sawyer::Resource:0x007ffa460e48c0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460e48c0>>, @attrs={:display_name=>"Chicken Scheme"}>, :jruby18=>#<Sawyer::Resource:0x007ffa460e4370 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460e4370>>, @attrs={:display_name=>"JRuby (1.8 mode)"}>, :haskell=>#<Sawyer::Resource:0x007ffa460d7f08 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d7f08>>, @attrs={:display_name=>"Haskell"}>, :perl=>#<Sawyer::Resource:0x007ffa460d79e0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d79e0>>, @attrs={:display_name=>"Perl"}>, :smalltalk=>#<Sawyer::Resource:0x007ffa460d7490 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d7490>>, @attrs={:display_name=>"Smalltalk"}>, :python3=>#<Sawyer::Resource:0x007ffa460d6ef0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d6ef0>>, @attrs={:display_name=>"Python 3"}>, :java=>#<Sawyer::Resource:0x007ffa460d69a0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d69a0>>, @attrs={:display_name=>"Java"}>, :factor=>#<Sawyer::Resource:0x007ffa460d6478 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d6478>>, @attrs={:display_name=>"Factor"}>, :"c++"=>#<Sawyer::Resource:0x007ffa460d5fa0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d5fa0>>, @attrs={:display_name=>"C++"}>, :go=>#<Sawyer::Resource:0x007ffa460d5a00 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d5a00>>, @attrs={:display_name=>"Go"}>, :jruby19=>#<Sawyer::Resource:0x007ffa460d55a0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d55a0>>, @attrs={:display_name=>"JRuby (1.9 mode)"}>, :php=>#<Sawyer::Resource:0x007ffa460d5140 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d5140>>, @attrs={:display_name=>"PHP"}>, :lua=>#<Sawyer::Resource:0x007ffa460d4d08 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d4d08>>, @attrs={:display_name=>"Lua"}>, :scala=>#<Sawyer::Resource:0x007ffa460d48d0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d48d0>>, @attrs={:display_name=>"Scala"}>, :fsharp=>#<Sawyer::Resource:0x007ffa460d44e8 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d44e8>>, @attrs={:display_name=>"F#"}>, :io=>#<Sawyer::Resource:0x007ffa460d40b0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa460d40b0>>, @attrs={:display_name=>"Io"}>, :c=>#<Sawyer::Resource:0x007ffa4609fbd0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa4609fbd0>>, @attrs={:display_name=>"C"}>, :lolcode=>#<Sawyer::Resource:0x007ffa4609f748 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa4609f748>>, @attrs={:display_name=>"LOLCODE (via lci)"}>, :"sml-mlton"=>#<Sawyer::Resource:0x007ffa4609f310 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa4609f310>>, @attrs={:display_name=>"SML (MLton)"}>, :perl6=>#<Sawyer::Resource:0x007ffa4609eed8 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa4609eed8>>, @attrs={:display_name=>"Perl 6 (Rakudo Star)"}>, :ruby=>#<Sawyer::Resource:0x007ffa4609eaa0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa4609eaa0>>, @attrs={:display_name=>"Ruby"}>, :elixir=>#<Sawyer::Resource:0x007ffa4609e618 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa4609e618>>, @attrs={:display_name=>"Elixir"}>, :vbnet=>#<Sawyer::Resource:0x007ffa4609e1e0 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa4609e1e0>>, @attrs={:display_name=>"VB.NET"}>, :bash=>#<Sawyer::Resource:0x007ffa4609dd58 @_agent=<Sawyer::Agent http://eval.so/api>, @_rels=#<Sawyer::Relation::Map: []>, @_fields=#<Set: {:display_name}>, @_metaclass=#<Class:#<Sawyer::Resource:0x007ffa4609dd58>>, @attrs={:display_name=>"Bash"}>}>>
[4] pry(main)> agent.call :get, '/languages'
=> #<Sawyer::Response: 404 @rels={} @data="\n\n<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<title>Action not found</title>\n\t\t<link rel=\"shortcut icon\" href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlFJREFUeNqUU8tOFEEUPVVdNV3dPe8xYRBnjGhmBgKjKzCIiQvBoIaNbly5Z+PSv3Aj7DSiP2B0rwkLGVdGgxITSCRIJGSMEQWZR3eVt5sEFBgTb/dN1yvnnHtPNTPG4PqdHgCMXnPRSZrpSuH8vUJu4DE4rYHDGAZDX62BZttHqTiIayM3gGiXQsgYLEvATaqxU+dy1U13YXapXptpNHY8iwn8KyIAzm1KBdtRZWErpI5lEWTXp5Z/vHpZ3/wyKKwYGGOdAYwR0EZwoezTYApBEIObyELl/aE1/83cp40Pt5mxqCKrE4Ck+mVWKKcI5tA8BLEhRBKJLjez6a7MLq7XZtp+yyOawwCBtkiBVZDKzRk4NN7NQBMYPHiZDFhXY+p9ff7F961vVcnl4R5I2ykJ5XFN7Ab7Gc61VoipNBKF+PDyztu5lfrSLT/wIwCxq0CAGtXHZTzqR2jtwQiXONma6hHpj9sLT7YaPxfTXuZdBGA02Wi7FS48YiTfj+i2NhqtdhP5RC8mh2/Op7y0v6eAcWVLFT8D7kWX5S9mepp+C450MV6aWL1cGnvkxbwHtLW2B9AOkLeUd9KEDuh9fl/7CEj7YH5g+3r/lWfF9In7tPz6T4IIwBJOr1SJyIGQMZQbsh5P9uBq5VJtqHh2mo49pdw5WFoEwKWqWHacaWOjQXWGcifKo6vj5RGS6zykI587XeUIQDqJSmAp+lE4qt19W5P9o8+Lma5DcjsC8JiT607lMVkdqQ0Vyh3lHhmh52tfNy78ajXv0rgYzv8nfwswANuk+7sD/Q0aAAAAAElFTkSuQmCC\">\n\t    <style>\n\t\t    html, body, pre {\n\t\t        margin: 0;\n\t\t        padding: 0;\n\t\t        font-family: Monaco, 'Lucida Console', monospace;\n\t\t        background: #ECECEC;\n\t\t    }\n\t\t    h1 {\n\t\t        margin: 0;\n\t\t        background: #AD632A;\n\t\t        padding: 20px 45px;\n\t\t        color: #fff;\n\t\t        text-shadow: 1px 1px 1px rgba(0,0,0,.3);\n\t\t        border-bottom: 1px solid #9F5805;\n\t\t        font-size: 28px;\n\t\t    }\n\t\t    p#detail {\n\t\t        margin: 0;\n\t\t        padding: 15px 45px;\n\t\t        background: #F6A960;\n\t\t        border-top: 4px solid #D29052;\n\t\t        color: #733512;\n\t\t        text-shadow: 1px 1px 1px rgba(255,255,255,.3);\n\t\t        font-size: 14px;\n\t\t        border-bottom: 1px solid #BA7F5B;\n\t\t    }\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<h1>Action not found</h1>\n\n\t\t<p id=\"detail\">\n\t\t\tFor request 'GET /languages'\n\t\t</p>\n\n\t</body>\n</html>\n\n\n\n\n\n\n\n">
@mislav
Copy link
Contributor

mislav commented Feb 17, 2014

http://eval.so/api + languages = http://eval.so/api/languages
http://eval.so/api + /languages = http://eval.so/languages

The initial slash matters. This is by design. It signifies that this URL starts from the root (the same as absolute/relative URLs distinction in hyperlinks)

@ghost
Copy link
Author

ghost commented Feb 17, 2014

Ahh, I see. Thanks for the explanation.

@ghost ghost closed this as completed Feb 17, 2014
tjukes pushed a commit to Giftbit/lightrail-stripe-ruby that referenced this issue Jul 25, 2017
Note this means that when paths are passed to the connection object (eg for ) they now need to *not* be prefixed by a slash (see [this Github issue](lostisland/faraday#346)).
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant