I am trying to build an app that will contain some YouTube videos.
I am using YouTube's API and accessing data using Alamofire but my attempts of data retrieval lead to the following error:
{
error =
{
code = 404;
errors =({
domain = "youtube.playlist";
location = channelId;
locationType = parameter;
message = "Channel not found.";
reason = channelNotFound;
}
);
message = "Channel not found.";
};
}
This is the contents of my viewDidLoad
let API_KEY = "*********"
let UPLOADS_PLAYLIST_ID = "PL28aSZBaDzoatmISten8xeFPPuva7l8s5"
let CHANNEL_ID = "PL28aSZBaDzoatmISten8xeFPPuva7l8s5"
let parameters =["part":"snippet","channelId":CHANNEL_ID,"playListId":UPLOADS_PLAYLIST_ID,"key":API_KEY]
Alamofire.request("https://www.googleapis.com/youtube/v3/playlists", parameters: parameters, encoding: URLEncoding.default, headers: nil).responseJSON { (response) in
if let JSON = response.result.value
{
print(JSON)
}
}
First go to youtube and find the channel name and and put into
let CHANNEL_ID = "properchannel"
Related
I'm attempting to access an api using my username and api key. An example they give, which I believe is .NET, is:
Public Sub GET_Products()
Dim request As HttpWebRequest = WebRequest.Create("https://api.ssactivewear.com/v2/products/?style=39")
request.Method = "GET"
request.Credentials = New NetworkCredential("YOurCustomerNumber", "YourAPIKey")
Try
Dim response As HttpWebResponse = request.GetResponse
Dim StreamReader As New StreamReader(response.GetResponseStream())
Result = StreamReader.ReadToEnd
If response.StatusCode = HtppStatusCode.OK Then
Products = serializer.Deserialize(Of List(Of Sku))(Result)
Else
End If
Catch ex As Exception
End Try
End Sub
I've used the following to test the request for a response:
guard let url = URL(string: "https://api.ssactivewear.com/v2/products/") else { return }
let username = "myusername"
let password = "myapikey"
AF.request(url).authenticate(username: username, password: password).responseJSON { response in
print("Request: \(String(describing: response.request))")
print("Response: \(String(describing: response.response))")
print("HeaderFields: \(String(describing: response.request?.allHTTPHeaderFields))")
if let json = response.value {
print("JSON: \(json)")
//self.responseText.text = "JSON: \(json)"
}
if let error = response.error {
print("ERROR: \(error.localizedDescription)")
//self.responseText.text = "ERROR: \(error.localizedDescription)"
}
}
This fails authentication because no authentication header is sent. I believe I read this is expected behavior but didn't find a solution.
create APIMiddle class:
class APIManager
{
class func headers() -> HTTPHeaders
{
let headers: HTTPHeaders = [
"Content-Type": "application/json",
"Accept": "application/json"
]
return headers
}
}
your api call:
let request = AF.request(path, method: .post, parameters: params, encoding: JSONEncoding.default, headers: APIManager.headers(), interceptor: nil)
request.responseDecodable(of: UserModel?.self) {(resposnse) in
let user = resposnse.value
print(user)
}
Alamofire's authenticate method adds a URLCredential to the Request which is used to respond to server challenges. If the server never sends a challenge for those credentials, the credentials will never be used. api.ssactivewear.com appears to use HTTP Basic auth, which should work fine, but I couldn't find any specific documentation about that. There may be other requirements to properly make a request to the API. I suggest you investigate those requirements as well as the actual network traffic being sent to see what's actually happening.
I am using google drive SDK for folder creation, but unable to create. I am able to login and get all files and folder but unable to create it.
I am using swift and used this code
let metaData = GTLRDrive_File()
metaData.name = "xyz"
metaData.mimeType = "application/vnd.google-apps.folder"
let querys = GTLRDriveQuery_FilesCreate.query(withObject: metaData, uploadParameters: nil)
querys.fields = "id"
//service.executeQuery(querys, delegate: self, didFinish: nil)
self.service.executeQuery(querys) { (ticket:GTLRServiceTicket, object:Any?, error:Error?) in
// Put your completion code here
}
But unable to create folder. Can anyone help me out. Thanks in advance.
func chilkatTest() {
var success: Bool = true
// It requires the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
// This example uses a previously obtained access token having permission for the
// Google Drive scope.
let gAuth = CkoAuthGoogle()
gAuth.AccessToken = "GOOGLE-DRIVE-ACCESS-TOKEN"
let rest = CkoRest()
// Connect using TLS.
var bAutoReconnect: Bool = true
success = rest.Connect("www.googleapis.com", port: 443, tls: true, autoReconnect: bAutoReconnect)
// Provide the authentication credentials (i.e. the access token)
rest.SetAuthGoogle(gAuth)
// -------------------------------------------------------------------------
// A multipart upload to Google Drive needs a multipart/related Content-Type
rest.AddHeader("Content-Type", value: "multipart/related")
// Specify each part of the request.
// The 1st part is JSON with information about the file.
rest.PartSelector = "1"
rest.AddHeader("Content-Type", value: "application/json; charset=UTF-8")
let json = CkoJsonObject()
json.AppendString("name", value: "testHello.txt")
json.AppendString("description", value: "A simple file that says Hello World.")
json.AppendString("mimeType", value: "text/plain")
// To place the file in a folder, we must add a parents[] array to the JSON
// and list the folder id's. It's possible for a file to be in multiple folders at once
// if it has more than one parent. If no parents are specified, then the file is created
// in the My Drive folder.
// Note: We'll assume we already have the id if the folder. It is the id's that are specified here,
// not the folder names.
var parents: CkoJsonArray? = json.AppendArray("parents")
var folderId: String? = "0B53Q6OSTWYolY2tPU1BnYW02T2c"
parents!.AddStringAt(-1, value: folderId)
parents = nil
rest.SetMultipartBodyString(json.Emit())
// The 2nd part is the file content, which will contain "Hello World!"
rest.PartSelector = "2"
rest.AddHeader("Content-Type", value: "text/plain")
var fileContents: String? = "Hello World!"
rest.SetMultipartBodyString(fileContents)
var jsonResponse: String? = rest.FullRequestMultipart("POST", uriPath: "/upload/drive/v3/files?uploadType=multipart")
if rest.LastMethodSuccess != true {
print("\(rest.LastErrorText)")
return
}
// A successful response will have a status code equal to 200.
if rest.ResponseStatusCode.integerValue != 200 {
print("response status code = \(rest.ResponseStatusCode.integerValue)")
print("response status text = \(rest.ResponseStatusText)")
print("response header: \(rest.ResponseHeader)")
print("response JSON: \(jsonResponse!)")
return
}
// Show the JSON response.
json.Load(jsonResponse)
// Show the full JSON response.
json.EmitCompact = false
print("\(json.Emit())")
// A successful response looks like this:
// {
// "kind": "drive#file",
// "id": "0B53Q6OSTWYoldmJ0Z3ZqT2x5MFk",
// "name": "Untitled",
// "mimeType": "text/plain"
// }
// Get the fileId:
print("fileId: \(json.StringOf("id"))")
}
Link for libraries needed:-
Download libraries
Include CkoAuthGoogle, CkoRest and CkoJsonObject header files in your project.
It is basically due to the scope, I have to give kGTLRAuthScopeDriveFile in scope area
private let scopes = [kGTLRAuthScopeDriveReadonly,kGTLRAuthScopeDriveFile]
and rest same in google
func folder(){
let metadata = GTLRDrive_File()
metadata.name = "eBilling"
metadata.mimeType = "application/vnd.google-apps.folder"
let querys = GTLRDriveQuery_FilesCreate.query(withObject: metadata, uploadParameters: nil)
querys.fields = "id"
self.service.executeQuery(querys, completionHandler: {(ticket:GTLRServiceTicket, object:Any?, error:Error?) in
if error == nil {
self.listFiles()
}
else {
print("An error occurred: \(error)")
}
})
}
Swift 5
If you are looking to just create a folder without uploading a file with it,
I was able to create a drive folder using Google's REST endpoint like this.
This function takes the auth token and a filename and parameters to create a URLRequest that can then be sent off within a URLSession.
func createFolderRequest(authToken: String, folderName: String) -> URLRequest {
let headers = [
"Content-Type": "multipart/related; boundary=123456789",
"Authorization": "Bearer " + authToken
]
let body =
"""
--123456789
Content-Type: application/json
{
"name": "\(folderName)",
"mimeType": "application/vnd.google-apps.folder"
}
--123456789--
"""
var request = URLRequest(url: URL(string: "https://www.googleapis.com/upload/drive/v3/files")!)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = body.data(using: .utf8)
request.addValue(String(body.lengthOfBytes(using: .utf8)), forHTTPHeaderField: "Content-Length")
return request
}
I referenced the google docs for multipart file uploads here
I have requested the current user and from the user have requested the saved tracks of the user. When making the call to the api it succeeds and I am able to convert the response into a Spotify track object, but when I access the fields of the object the values come back as the default values. I parsed this response in the same manner as I did to get the current user but it didn't work this time. Any ideas on the cause?
let savedTracksRequestHeaders: HTTPHeaders = [
"Authorization": "Bearer " + accessToken!,
]
let params = ["limit": "1"]
var userSong = SPTTrack.init()
Alamofire.request("https://api.spotify.com/v1/me/tracks", method:
.get, parameters: params, headers:
savedTracksRequestHeaders).responseJSON { response in
print("Saved Track Response")
debugPrint(response)
do {
// executes with no errors
try userSong = SPTTrack.init(from: response.data, with:
response.response)
print("user songs")
// when the variable is used all fields are default
// values
print(userSong.popularity)
} catch is Error {
print("load songs failed")
}
}
I am a .net developer but very new to iOS and swift development, just need help with consuming Web API using Swift2
The Asp.net Web API has been built with OAuth2 authentication, published to my Azure VM server with SSL certificate installed. The API site itself works properly, tested through Postman
However I got stuck when started writing first few lines of code in Swift trying to get Authentication token. After reading some online tutorials I decided to engage Alamofire, and produced below codes snippet:
func GetToken() {
let params = [
"grant_type" : "password",
"username" : "123456#qq.com",
"password" : "averygoodpassword"
]
let headers = [
"Content-Type" : "application/x-www-form-urlencoded"
]
request(.POST, "https://api.example.com/token",
parameters: params,
headers: headers,
encoding: .JSON)
.responseJSON { request, response, result in
print (request)
print (response?.description)
print (result)
switch result {
case .Success(let JSON):
print("Success with JSON: \(JSON)")
case .Failure(let data, let error):
print("Request failed with error: \(error)")
if let data = data {
print("Response data: \(NSString(data: data, encoding: NSUTF8StringEncoding)!)")
}
}
}
}
It ends up with below output in Xcode which didn't seem to be OK. The error = unsupported_grant_type told me that the request were sent to server but the parameters were not sent with request properly. I really cannot figure out the reason and solution, had been digging on Internet for a few days but still feeling desperate with it. Can anyone help please? Even if someone can provide a pure swift solution without any 3rd party library will be greatly helpful. Thanks!
Xcode output:
Optional( { URL: https://api.example.com/token })
Optional(" { URL: https://api.example.com/token } { status code: 400, headers {\n \"Access-Control-Allow-Headers\" = \"Content-Type\";\n \"Access-Control-Allow-Methods\" = \"GET, POST, PUT, DELETE, OPTIONS\";\n \"Access-Control-Allow-Origin\" = \"*\";\n \"Cache-Control\" = \"no-cache\";\n \"Content-Length\" = 34;\n \"Content-Type\" = \"application/json;charset=UTF-8\";\n Date = \"Fri, 30 Sep 2016 10:30:31 GMT\";\n Expires = \"-1\";\n Pragma = \"no-cache\";\n Server = \"Microsoft-IIS/8.5\";\n \"X-Powered-By\" = \"ASP.NET\";\n} }")
SUCCESS
Success with JSON: {
error = "unsupported_grant_type";
}
I had a similar problem trying to POST to MailGun for some automated emails I was implementing in an app.
I was able to get this working properly with a large HTTP response. I put the full path into Keys.plist so that I can upload my code to github and broke out some of the arguments into variables so I can have them programmatically set later down the road.
// Email the FBO with desired information
// Parse our Keys.plist so we can use our path
var keys: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("Keys", ofType: "plist") {
keys = NSDictionary(contentsOfFile: path)
}
if let dict = keys {
// variablize our https path with API key, recipient and message text
let mailgunAPIPath = dict["mailgunAPIPath"] as? String
let emailRecipient = "bar#foo.com"
let emailMessage = "Testing%20email%20sender%20variables"
// Create a session and fill it with our request
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: mailgunAPIPath! + "from=FBOGo%20Reservation%20%3Cscheduler#<my domain>.com%3E&to=reservations#<my domain>.com&to=\(emailRecipient)&subject=A%20New%20Reservation%21&text=\(emailMessage)")!)
// POST and report back with any errors and response codes
request.HTTPMethod = "POST"
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
The Mailgun Path is in Keys.plist as a string called mailgunAPIPath with the value:
https://API:key-<my key>#api.mailgun.net/v3/<my domain>.com/messages?
I'm slightly opposed to using 3rd party libraries, especially for small things like a http POST and this seems like a much more maintainable solution to me. Anyways, hope this helps, let me know if you have any questions!
I am using Azure Mobile Services API endpoint to return a private shared access signature URL to my azure storage container like so:
var blobService = azure.createBlobService(accountName, key, host);
blobService.createContainerIfNotExists(containerName, function(err) {
if (err) {
cb(err, null);
return;
}
// Generate a 5 minute access
var expiryDate = minutesFromNow(5);
var sharedAccessPolicy = {
AccessPolicy: {
Permissions: azure.Constants.BlobConstants.SharedAccessPermissions.WRITE,
Expiry: expiryDate
}
};
// Generate the URL with read access token
var sasURL = blobService.generateSharedAccessSignature(containerName, blobName, sharedAccessPolicy);
var urlForDownloading = sasURL.baseUrl + sasURL.path + '?' + qs.stringify(sasURL.queryString);
cb(null, urlForDownloading);
});
function minutesFromNow(minutes) {
var date = new Date();
date.setMinutes(date.getMinutes() + minutes);
return date;
};
I then return this URL to my iOS client to upload the file and process it as:
client.invokeAPI("document/\(document.idValue).\(document.fileExtension)",
body: nil,
HTTPMethod: "PUT",
parameters: nil,
headers: nil) { result, response, error in
if let dictResult = result as? NSDictionary {
// Get the SAS URL to write directly to the blob storage
if let location = dictResult["location"] as? String {
let url = NSURL(string: location)
let request = NSURLRequest(URL: url)
let uploadTask = session.uploadTaskWithRequest(request, fromFile: localFile) { data, response, error in
if completionBlock != nil {
let success = (error == nil && httpResponse.statusCode == 200)
completionBlock!(success)
}
}
}
}
}
uploadTask.resume()
The iOS client gets a 404 response with a message of
<?xml version="1.0" encoding="utf-8"?><Error><Code>ResourceNotFound</Code><Message>The specified resource does not exist.
The container does exist in the storage account and requests to get blobs from the container with the access keys are successful. This new blob won't exist as it is a new upload, but why am I getting a 404 for a write request to the container?
Found the solution...
let request = NSURLRequest(URL: url) produces a GET request and even passing it to uploadTaskWithRequest persists this request type, whereas I thought this call would change it to a PUT or POST request signifying the upload.
Defining the iOS request as
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "PUT"
was successful. And the response returned was a 201 created.