title: Bad Request when posting JSON to Flask endpoint in unit test
body: <p>I found a load of questions about people trying to post JSON to a Flask app, but none of those are quite the problem I have here.</p>
  
  <p>I have a simple REST API, built using Flask and Flask-JWT, which is working fine through a browser, but I've hit a block with my unit tests.  The app is an App Engine app and runs fine on the local dev server and on App Engine.  I'm running my unit tests with <code>python -m unittest &lt;module&gt;</code>.</p>
  
  <p>I have a basic Flask app created using a simple factory:</p>
  
  <pre><code>def create_app(name=__name__, cfg):
      app = Flask(name)
      app.config.update(cfg)
  
      CORS(app)
      JWT(app, auth_handler, identity_handler)
  
      @app.route('/api/v1/ping', methods=['GET'])
      def handle_ping():
          return jsonify({'message': 'pong'})
  
      # other routes ...
  </code></pre>
  
  <p>In the above, <code>JWT</code> expects an <a href="https://pythonhosted.org/Flask-JWT/index.html#flask_jwt.JWT.authentication_handler" rel="nofollow"><code>authentication_handler</code></a>, which I have implemented:</p>
  
  <pre><code>def auth_handler(identity, secret):
      # validate identity and secret
      return User(...)
  </code></pre>
  
  <p>My client is Angular.js so I am posting JSON to this endpoint. This is all working fine in a browser, or with curl:</p>
  
  <pre><code>$ curl -H "content-type:application/json" -d '{"username":"jackripper@example.com","password":"crm114"}'   http://localhost:8080/api/v1/auth
  </code></pre>
  
  <p>giving me a <code>200 OK</code> and an access token in the response.</p>
  
  <p>My simple test cases go something like this:</p>
  
  <pre><code>conf = {
       'DEBUG': False,
      'TESTING': True,
      'SECRET_KEY': 'MoveAlongTheresNothingToSeeHere',
      'JWT_AUTH_URL_RULE': '/api/v1/auth'
  }
  
  class FlaskRouteTests(unittest.TestCase):
      def setUp(self):
          api = factory.create_app(__name__, conf)
          self.app = api.test_client()
  
      def tearDown(self):
          pass
  
      def testRoute(self):
          # This test works just fine
          resp = self.app.get('/api/v1/ping')
          self.assertEqual(resp.status, "200 OK", "Status should be 200, was %s" % resp.status)
  
      def testAuth(self):
          # This test does not work
          resp = self.app.post('http://localhost:8080/api/v1/auth',
                           data="{'username': 'jackripper@example.com', 'password': 'crm114'}",
                           content_type='application/json', charset='UTF-8')
          self.assertEqual(resp.status, "200 OK", "Status should be 200, was %s" % resp.status)
  </code></pre>
  
  <p>The plain old <code>GET</code> test (<code>testRoute()</code>) works just fine but <code>testAuth()</code> gives me a <code>400 Bad Request</code> and I can't figure out why.</p>
  
  <p>If I look at the <em>werkzeug</em> <code>environ</code> immediately before it sends the request to my Flask app, I see this:</p>
  
  <pre><code>{
   'SERVER_PORT': '8080',
   'SERVER_PROTOCOL': 'HTTP/1.1',
   'SCRIPT_NAME': '',
   'wsgi.input': &lt;_io.BytesIO object at 0x111fa8230&gt;,
   'REQUEST_METHOD': 'POST',
   'HTTP_HOST': 'localhost:8080',
   'PATH_INFO': '/api/v1/auth',
   'wsgi.multithread': False,
   'QUERY_STRING': '',
   'HTTP_CONTENT_TYPE': 'application/json',
   'HTTP_CONTENT_LENGTH': '53',
   'CONTENT_LENGTH': '53',
   'wsgi.version': (1, 0),
   'SERVER_NAME': 'localhost',
   'wsgi.run_once': False,
   'wsgi.errors': &lt;open file '&lt;stderr&gt;', mode 'w' at 0x10fd2d1e0&gt;,
   'wsgi.multiprocess': False,
   'flask._preserve_context': False,
   'wsgi.url_scheme': 'http',
   'CONTENT_TYPE': u'application/json'
  }
  </code></pre>
  
  <p>So, the content-type is correctly set and if I read the contents of the <code>wsgi.input</code> (<code>BytesIO.getvalue()</code>) I see <code>{'username': 'jackripper@example.com', 'password': 'crm114'}</code></p>
  
  <p>The request seems to be failing somewhere <em>before</em> it even hits my <code>auth_handler</code>, so somewhere in werkzeug or Flask.</p>
  
  <ul>
  <li>The werkzeug <code>EnvironBuilder</code> interprets the data as a <code>str</code> and converts it to a <code>BytesIO</code> stream - I don't know if this is expected.</li>
  <li>I've tried POSTing data both as a string: <code>data="{'username': 'jackripper@example.com', 'password': 'password'}"</code> and as a dict: <code>data={'username': 'jackripper@example.com', 'password': 'password'}</code>, but it seems to make no difference. </li>
  </ul>
  
  <p><strong>So, my question</strong>:
  How do I post JSON to an endpoint in a unit test with <code>Flask.test_client()</code>?  Am I missing something obvious?</p>