Swift 4 Rest API oauth v1.0 and base signature

Quick background, I am extremely new in this realm. I am aware that this type of question has been asked before and answered successfully. The issue that I am experiencing is caused by the inability to wrap my head around the process of establishing the connection. I have spent hours (into days) searching for the answer and I am still unsuccessful. This has become my "white whale" so to speak.


I am using Xcode 9 with Swift version 4. Many of the answers I come across use Objective-C and I can't see a way to mix and match. So I would like to UNDERSTAND why I am unable to connect and the correct process to connect so I can write the code with the understanding of what I am doing. Lastly, I have signed up (and completed) a few paid Udemy courses to try and learn the process correctly. I have been able to connect to API sources but OAuth 1 is tripping me up. Any constructive help would be incredibly appreciated.


Background:

I am attempting to connect to the Fat Secret database. I would like to connect a search bar to the food.search functionality and also the food.get for another search bar.

Company- FatSecret URL for API- platform.fatsecret.com/rest/server.api

URL to FatSecret documentation (I have gone through this MANY times)-

http:/ let task = URLSession.shared.dataTask(with: url) { 
(data, response, error) in 
if error != nil { 
print("success") 
} 
task.resume()

The above code is what I used to establish the connection. I receive "success" in the console so I expanded my parameters.

 
let url = URL(string: "I am unable to post more than 2 links due to my rep so I put {space} in the above url to circumvent the error. I used the listed url from the parameters")! 
let task = URLSession.shared.dataTask(with: url) { 
(data, response, error) in 
if error != nil 
{ 
print(error) 
if let urlContent = data { 
do { 
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject 
print(jsonResult) 
} catch { 
} 
task.resume()


*The above information was pulled from a different source (Stack Overflow) where I could not post more than two links.*


The above code produces nothing in the console. I believe (sorry for my ignorance) that the reason I am not getting a response is because I am not sending any authorization in the request, nor am I am sending in the correct encoding. I imagine that I can create the parameters by var/let statements and then call on those statements but I am not able to see the way to do that. I could likely also store all of my connection information in a different swift file or class and call on that when I need to access data. This base signature is required with every request. I have to imagine that best practice would be setting it up that way but again, I can't visualization the process. It becomes a trial and error process that results in incredible frustration.


Again, any help would be incredibly appreciated. I apologize for the length of this post. Thank you for taking the time to read this post.

You should better show your code with the right indentations, which helps you to find some simple mistakes.

And you should not ignore errors or unexpected results silently, which may contain some useful info for debugging.


Try this code and tell us what you get:

        let url = URL(string: "Your actual URL string stating with scheme (i.e. 'http:...')")!
        let task = URLSession.shared.dataTask(with: url) {
            (data, response, error) in
            if let error = error {
                print(error)
                return
            }
            guard let urlContent = data else {
                print("`data` is nil")
                return
            }
            do {
                let jsonResult = try JSONSerialization.jsonObject(with: urlContent)
                print(jsonResult)
            } catch {
                print(error)
            }
        }
        task.resume()


And some more:


You have no need to specify the option: `JSONSerialization.ReadingOptions.mutableContainers`.

(In almost all cases, you would not `mutate` the containers.)


You have no need to cast the result of `JSONSerialization.jsonObject(with:)` to `AnyObject`.

(Once you confirm you have received the right result, you'll find a better type to cast to.)


One last thing that I should note here:

OAuth 1.0 is a complex protocol even for experienced programmers, you may need to jump over many high hurdles after you successfully get the result from the above code...

Thank you for your reply! My apologies on the formatting. I will correct that moving forward.


import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        /

    let url = URL(string: "https:/
    let task = URLSession.shared.dataTask(with: url) {
        (data, response, error) in
        if let error = error {
            print(error)
            return
        }
        guard let urlContent = data else {
            print("`data` is nil")
            return
        }
        do {
            let jsonResult = try JSONSerialization.jsonObject(with: urlContent)
            print(jsonResult)
        } catch {
            print(error)
        }
    }
    task.resume()


    }
}


I ran this code and it produce the following message in the console:


Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}

Yesterday, I spent about 9 hours (saddens me to even call it out in a number), trying to run different syntax to connect to the server. The closest I got was connecting to the HTML side of things but obviously that is not an API call, so no data could be parsed.

The error message is output from the line 22 `print(error)` of your latest code.

Which is saying the `urlContent` you have received is not a valid JSON.


You can check the content with inserting this line just before the line 18 `do {`:

            print(String(data: urlContent, encoding: .utf8) ?? "non UTF-8")

It looks like it is due to missing oauth parameters. I am also missing the rest of the signature as well. Here is the error message for the reference:


<?xml version="1.0" encoding="utf-8" ?>

<error xmlns="http:/

<code>2</code>

<message>Missing required oauth parameter: oauth_signature_method</message>

</error>

Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}

My signature base string would need to include the following information:


HTTP MethodWe support both HTTP methods GET and POST.Request URL

The URL to make API calls is: platform . fatsecret . com / rest / server . api

Normalized Parameters

Please refer to the FatSecret REST API documentation for the full parameter list for each method, but for OAuth authentication the following parameters are required for every request:

oauth_consumer_keyYour consumer key- I have this alreadyoauth_signature_methodWe only support "HMAC-SHA1"oauth_timestampThe date and time, expressed in the number of seconds since January 1, 1970 00:00:00 GMT. The timestamp value must be a positive integer and must be equal or greater than the timestamp used in previous requestsoauth_nonceA randomly generated string for a request that can be combined with the timestamp to produce a unique valueoauth_versionMust be "1.0" I then need to include the following parameters:

All request parameters (i.e. the HTTP Method, Request URL and Normalized Parameters) must be encoded using the [RFC3986] percent-encoding (%xx) mechanism and concatenated by an '&' character.

E.G.: A request is made using the POST HTTP method with the following parameters:

  • oauth_consumer_key=demo
  • oauth_signature_method=HMAC-SHA1
  • oauth_timestamp=12345678
  • oauth_nonce=abc
  • oauth_version=1.0
  • a=foo
  • z=bar



I believe that I was able to work around the timestamp with something like:

let timestamp = Date().timeIntervalSince1970


I included that in the string (which I don't think is the correct process). I tired different variations of the URL but I dont think any of them were responding correctly. I need to send a base signature, that's encoded, with every request that is made. Setting up the base signature and establishing the connection is what I have been failing at.



*Update*

My apologies on the delay. I posted this shortly after you replied last evening but due to external links, I was stuck "currently being moderated." I have removed external links.

First of all, you have no need to represent your apologies for the delay. I would be unable to write any replies when I'm busy, that might be weeks.

You should better try to get more attention to your issue, starting a new thread would be one way.


Anyway, sending a valid request based on OAuth 1.0 is not an easy thing. You need to go step by step.

So, do not miss this sentence --

Please refer to the FatSecret REST API documentation for the full parameter list for each method


You need to find the method you want to call, writing something with pseudo parameters like a=foo or z=bar does not help.

And then find the full parameter list for the method.

Thank you for your assistance. I will continue to try working through that document to create a base signature. I really appreciate the input!

Swift 4 Rest API oauth v1.0 and base signature
 
 
Q