Alamofire variables or parameters support in url path - swift

Does Alamofire support variables in a url path, I have looked for an example but i can't find it.
I have looked in their their docs and unit tests.
It is pretty common for apis to be written with url support for the following:
http://someapi.com/users/{user}/profile
I have looked through their examples in URLEncoding, but i cant find nothing that does the above, examples only seem to add query parameters.

Alamofire relies on the Foundation URL struct, so you need to look there.
URLs offer several different mechanisms for constructing them, the one you could be using is path component, for example:
var url = URL(string: "http://someapi.com/users")
let user = "user"
url?.appendPathComponent(user)
url?.appendPathComponent("profile")
Additionally, you could leverage enums to clean up a bit and maybe construct URLs from strings, something like this:
enum MyURLScheme {
case profile(user: String)
var url: URL? {
switch self {
case .profile(let user):
let url = URL(string: "http://someapi.com/users/\(user)/profile")
return url
}
}
}
let profileURL = MyURLScheme.profile(user: "user").url
EDIT: You can also use Alamofire Router class for building requests, taken from here:
enum Router: URLRequestConvertible {
case search(query: String, page: Int)
static let baseURLString = "https://example.com"
static let perPage = 50
// MARK: URLRequestConvertible
func asURLRequest() throws -> URLRequest {
let result: (path: String, parameters: Parameters) = {
switch self {
case let .search(query, page) where page > 0:
return ("/search", ["q": query, "offset": Router.perPage * page])
case let .search(query, _):
return ("/search", ["q": query])
}
}()
let url = try Router.baseURLString.asURL()
let urlRequest = URLRequest(url: url.appendingPathComponent(result.path))
return try URLEncoding.default.encode(urlRequest, with: result.parameters)
}
}
Alamofire.request(Router.search(query: "foo bar", page: 1))

Related

Returning parsed JSON data using Alamofire?

Hello new to Swift and Alamofire,
The issue i'm having is when I call this fetchAllUsers() the code will return the empty users array and after it's done executing it will go inside the AF.request closure and execute the rest.
I've done some research and I was wondering is this is caused by Alamofire being an Async function.
Any suggestions?
func fetchAllUsers() -> [User] {
var users = [User]()
let allUsersUrl = baseUrl + "users/"
if let url = URL(string: allUsersUrl) {
AF.request(url).response { response in
if let data = response.data {
users = self.parse(json: data)
}
}
}
return users
}
You need to handle the asynchrony in some way. This this means passing a completion handler for the types you need. Other times it means you wrap it in other async structures, like promises or a publisher (which Alamofire also provides).
In you case, I'd suggest making your User type Decodable and allow Alamofire to do the decoding for you.
func fetchAllUsers(completionHandler: #escaping ([User]) -> Void) {
let allUsersUrl = baseUrl + "users/"
if let url = URL(string: allUsersUrl) {
AF.request(url).responseDecodable(of: [User].self) { response in
if let users = response.value {
completionHandler(users)
}
}
}
}
However, I would suggest returning the full Result from the response rather than just the [User] value, otherwise you'll miss any errors that occur.

What does " Value of tuple type '(String, JSON)' has no member 'subscript' " refer to in Xcode?

So for my file I am trying to use Alamofire to make a request in order to get Photos from Flickr using their API.
I am using CoreData, Alamofire, and SwiftyJSON
The method is as follow:
func getImagesFromFlickr(_ selectedPin: Pin, _ page: Int, _ completionHandler: #escaping (_ result: [Photo]?, _ error: NSError?) -> Void) {
/* Set Parameters */
let methodParameters: [String:String] = [
Constants.FlickrParameterKeys.Method: Constants.FlickrParameterValues.SearchMethod,
Constants.FlickrParameterKeys.APIKey: Constants.FlickrParameterValues.APIKey,
Constants.FlickrParameterKeys.BoundingBox: bboxString(longitude:selectedPin.longitude , latitude: selectedPin.latitude),
Constants.FlickrParameterKeys.Latitude: "\(selectedPin.latitude)",
Constants.FlickrParameterKeys.Longitude: "\(selectedPin.longitude)",
Constants.FlickrParameterKeys.PerPage: "21",
Constants.FlickrParameterKeys.Page: "\(page)",
Constants.FlickrParameterKeys.SafeSearch: Constants.FlickrParameterValues.UseSafeSearch,
Constants.FlickrParameterKeys.Extras: Constants.FlickrParameterValues.MediumURL,
Constants.FlickrParameterKeys.Format: Constants.FlickrParameterValues.ResponseFormat,
Constants.FlickrParameterKeys.NoJSONCallback: Constants.FlickrParameterValues.DisableJSONCallback
]
/* Build the URL */
let url = flickrURLFromParameters(methodParameters)
/* Make the request with Alamofire */
Alamofire.request(url).validate(statusCode: 200..<300).responseJSON { (response) in
if response.result.isSuccess {
print("Success! Got the Images from Flickr!")
let flickrJSON : JSON = JSON(response.result.value!)
print(flickrJSON)
let photosDict = flickrJSON["photos"]
let photoArray = photosDict["photo"]
performUIUpdatesOnMain {
let context = CoreDataStack.getContext()
var imageUrlString = [Photo]()
for url in photoArray {
let urlString = String(url[Constants.FlickrResponseKeys.MediumURL])
let photo : Photo = NSEntityDescription.insertNewObject(forEntityName: "Photo", into: context ) as! Photo
photo.urlString = urlString
photo.pin = selectedPin
imageUrlString.append(photo)
CoreDataStack.saveContext()
}
completionHandler(imageUrlString, nil)
}
} else {
print("Error: \(String(describing: response.result.error))")
}
}
}
The error is within this line of code:
let urlString = String(url[Constants.FlickrResponseKeys.MediumURL])
I get this error in Xcode saying " Value of tuple type '(String, JSON)' has no member 'subscript' "
Any help with why I am getting this error is much appreciated.
Also, any recommendations on how I can implement this method better is much appreciated.
If you would like to take a look at my project it is under the branch called "Networking-with-Alamofire"
The link is here:
https://github.com/RobertoEfrainHernandez/Virtual-Tourist-Udacity/tree/Networking-with-Alamofire
If you look under the master branch I did my networking code using URLSessions and my goal for the Networking-with-Alamofire branch was to convert those networking methods using Alamofire and SwiftyJSON.
for url in photoArray
I suppose here url not always a dictionary, in your case you get a tuple (value1, value2) and obviously you cannot access parameters in tuple via subscript syntax.
You need to check JSON response and make some adjustments in mapping func

Alamofire Connect to Localhost

I want to connect to my localhost (homestead with laravel) to test my swift app. Therefore I use Alamofire to send data via my API to be saved in my database. When I connect to my staging server (in the cloud) everything works fine. But when I want to connect to my local machine (192.168.10.10) it doesn't work through the iOS app. Using the same connection via POSTMAN does work fine and I can access everything.
How do I need to configure Alamofire, that I can use my localhost IP to connect to my test database?
import Foundation
import Alamofire
enum Router: URLRequestConvertible {
static let baseURLString = "http://192.168.10.10/v1"
// == AUTHENTICIATION ==
case RegisterUser([String:AnyObject])
// match URLRequest routes to Alamofire methods
var URLRequest: NSMutableURLRequest {
var method: Alamofire.Method {
switch self {
// == AUTHENTICATION RESOURCE ==
case .RegisterUser:
return .POST
}
}
let result: (path: String, parameters: [String: AnyObject]?) = {
switch self {
// == AUTHENTICATION RESOURCE ==
case .RegisterUser(let newUser):
return ("mfusers", newUser)
}()
// Generate URL Request
let URL = NSURL(string: Router.baseURLString)!
// Append the path components from the result
let URLRequest = NSURLRequest(URL: URL.URLByAppendingPathComponent(result.path))
// Create URLRequest inclunding the encoded parameters
var parametersEncoding:Alamofire.ParameterEncoding {
switch method {
case .GET:
return .URL
case .POST, .PUT:
return .JSON
default:
return .JSON
}
}
let encoding = parametersEncoding
let (encodedRequest, _) = encoding.encode(URLRequest, parameters: result.parameters)
encodedRequest.HTTPMethod = method.rawValue
return encodedRequest
}
}

Encode parameters for URL Request

I created a Router to generate URL Requests.
enum Router: URLRequestConvertible {
static let baseURLString = "SERVERIP"
case GetAEDInRange(String)
// match URLRequest routes to Alamofire methods
var URLRequest: NSMutableURLRequest {
var method: Alamofire.Method {
switch self {
case .GetAEDInRange:
return .GET
}
}
// The output contains the path and parameters like ("aeds", newAED)
let result: (path: String, parameters: [String: AnyObject]?) = {
switch self {
case .GetAEDInRange(let parameters):
return ("aeds", parameters)
}()
// Generate URL Request
let URL = NSURL(string: Router.baseURLString)!
// Append the path components from the result
print(result.path)
let URLRequest = NSURLRequest(URL: URL.URLByAppendingPathComponent(result.path))
// Create URLRequest inclunding the encoded parameters
let encoding = Alamofire.ParameterEncoding.JSON
let (encodedRequest, _) = encoding.encode(URLRequest, parameters: result.parameters)
encodedRequest.HTTPMethod = method.rawValue
return encodedRequest
}
}
The output I expect is: http://BASEURL/v1/aed?latitude=100&longitude=100
When I use Alamofire to make a GET request with parameters attached, it works fine:
Alamofire.request(.GET, "http://SERVER/v1/aeds", parameters: parameters).responseJSON { (response) -> Void in
print(response.result.value)
}
When I use my router instead, the output is not generated as expected:
Alamofire.request(Router.GetAEDInRange(parameters)).responseJSON { (response) -> Void in
print(response.result.value)
}
When I print the URL String, I get: `http://SERVER/v1/aeds/``
How do I need to change my router? I struggle with the parameter component somehow.
Change this line
let encoding = Alamofire.ParameterEncoding.JSON
to this:
let encoding = Alamofire.ParameterEncoding.URLEncodedInURL
To understand the difference between Parameter Encodings in Alamofire take a look here.
Swift3
'Alamofire', '~> 4.0'
let parameters: [String: Any] = [
"parameter1" : data1,
"parameter2" : data2
]
Alamofire.request("https://httpbin.org/get", parameters: parameters, encoding: URLEncoding(destination: .queryString))

HTTP Request error using Alamofire

I am trying to access my MAMP database webservice using Alamofire. Following is my code:
Following is my router to construct my URL:
enum Router: URLRequestConvertible {
static let baseURLString = "http://pushchat.local:44447/"
case PostJoinRequest(String,String,String,String,String)
var URLRequest: NSURLRequest {
let (path: String, parameters: [String: AnyObject]) = {
switch self {
case .PostJoinRequest (let addPath, let userID, let token, let nickName, let secretCode):
let params = ["cmd": "join", "user_id": "\(userID)", "token": "\(token)", "name": "\(nickName)", "code": "\(secretCode)"]
return (addPath, params)
}
}()
let URL = NSURL(string: Router.baseURLString)
let URLRequest = NSURLRequest(URL: URL!.URLByAppendingPathComponent(path))
let encoding = Alamofire.ParameterEncoding.URL
return encoding.encode(URLRequest, parameters: parameters).0
}
}
Following is my viewdidload code:
Alamofire.request(.POST,Router.PostJoinRequest("api.php","12345678901234","12345678901234","ABCDEF","TopSecret")).responseJSON()
{(request, response, JSON, error) in
println(JSON)
}
Following is the compile error:
Cannot invoke 'responseJSON' with an argument list of type '((,,,)->_)'
Following is the declaration from Almofire for your reference.
:param: method The HTTP method.
:param: URLString The URL string.
:param: parameters The parameters. `nil` by default.
:param: encoding The parameter encoding. `.URL` by default.
:returns: The created request.
*/
// public func request(method: Method, _ URLString: URLStringConvertible, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL) -> Request {
// return request(encoding.encode(URLRequest(method, URLString), parameters: parameters).0)
// }
Please let me know why am I facing this issue while chaining and what is it that I am not doing right?
Thanks for your help.
Dev
The compiler error message is really misleading – there is no problem with responseJSON but with request method itself.
In fact compiler does not like your second parameter. You are passing URLRequestConvertible but URLStringConvertible is expected (see the signature you posted).
Maybe you wanted to call another version of request method:
//:param: URLRequest The URL request
//:returns: The created request.
public func request(URLRequest: URLRequestConvertible) -> Request
In that case you have to adjust your Router class and set HTTP method into NSURLRequest created inside. For example:
let URLRequest = NSMutableURLRequest(URL: URL!.URLByAppendingPathComponent(path))
URLRequest.HTTPMethod = "POST"
Note you will also probably need to use another parameter/data encoding.