title: Using POST and Auth with Firebase Database and Swift
body: <p>I need to use REST Api on my iOS app to post/retrieve data from my server. The app is set up with a key generator, which gets me a id token, and then I format my http request with the id. I know something about my url request is wrong, I just don't know what, but I get back a status code 400 whenever I run this. Any ideas where I went wrong?</p>
  <pre><code>    func postToFB() {
          
          let preURL = &quot;https://myapp.firebaseio.com/&quot;
          let url = URL(string: &quot;\(preURL)\(code)/calculatorDisplay.json?auth=\(idToken)&quot;)!
          var request = URLRequest(url: url)
          request.setValue(&quot;application/json&quot;, forHTTPHeaderField: &quot;Content-Type&quot;)
          request.httpMethod = &quot;PUT&quot;
          let parameters: [String: Any] = [
              &quot;field1&quot;: env.field1,
              &quot;field2&quot;: env.field2
          ]
          request.httpBody = parameters.percentEncoded()
          
          let task = URLSession.shared.dataTask(with: request) { data, response, error in
              guard let data = data,
                    let response = response as? HTTPURLResponse,
                    error == nil else {                                              // check for fundamental networking error
                  print(&quot;postCalcDataButtons error&quot;, error ?? &quot;Unknown error&quot;)
                  return
              }
              
              guard (200 ... 299) ~= response.statusCode else {                    // check for http errors
                  print(&quot;postCalcDataButtons = statusCode should be 2xx, but is \(response.statusCode)&quot;)
                  print(&quot;postCalcDataButtons response = \(response)&quot;)
                  return
              }
              
              let responseString = String(data: data, encoding: .utf8)
              print(&quot;postCalcDataButtons responseString = \(String(describing: responseString))&quot;)
          }
          
          task.resume()
      }
  </code></pre>
  <p>Here's the extensions that make the above code work:</p>
  <pre><code>extension Dictionary {
      func percentEncoded() -&gt; Data? {
          return map { key, value in
              let escapedKey = &quot;\(key)&quot;.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? &quot;&quot;
              let escapedValue = &quot;\(value)&quot;.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? &quot;&quot;
              return escapedKey + &quot;=&quot; + escapedValue
          }
          .joined(separator: &quot;&amp;&quot;)
          .data(using: .utf8)
      }
  }
  
  extension CharacterSet {
      static let urlQueryValueAllowed: CharacterSet = {
          let generalDelimitersToEncode = &quot;:#[]@&quot; // does not include &quot;?&quot; or &quot;/&quot; due to RFC 3986 - Section 3.4
          let subDelimitersToEncode = &quot;!$&amp;'()*+,;=&quot;
          
          var allowed = CharacterSet.urlQueryAllowed
          allowed.remove(charactersIn: &quot;\(generalDelimitersToEncode)\(subDelimitersToEncode)&quot;)
          return allowed
      }()
  }
  </code></pre>
  <p>Here's the response from the server:</p>
  <pre><code>&lt;NSHTTPURLResponse: 0x60000110a0a0&gt; { URL: https://calculonapp.firebaseio.com/zlwxrx/calculatorButtons.json?auth=authCode } { Status Code: 400, Headers {
      &quot;Access-Control-Allow-Origin&quot; =     (
          &quot;*&quot;
      );
      &quot;Cache-Control&quot; =     (
          &quot;no-cache&quot;
      );
      Connection =     (
          &quot;keep-alive&quot;
      );
      &quot;Content-Length&quot; =     (
          77
      );
      &quot;Content-Type&quot; =     (
          &quot;application/json; charset=utf-8&quot;
      );
      Date =     (
          &quot;Fri, 21 Aug 2020 21:16:43 GMT&quot;
      );
      Server =     (
          nginx
      );
      &quot;Strict-Transport-Security&quot; =     (
          &quot;max-age=31556926; includeSubDomains; preload&quot;
      );
  } }
  </code></pre>