I have the token in authorization Type Bearer Token in URLSession
I always use alamofire and swiftjson
Unfortunately I searched a lot and couldn't find the right way in URLSession
I have this token : 28|cSTxxxxxxxxxxxxxx Example
But it gives nil
struct model : Codable, Identifiable {
let id = UUID()
var name : String
}
class modelapiClass : ObservableObject {
#Published var modelBib : [model] = []
func getData() {
guard let url = URL(string: "https://xxxxxxxxxx") else {
return
}
let token = "28|cSTxxxxxxxxxxxxxx" Example
var request = URLRequest(url: url)
request.setValue( token, forHTTPHeaderField: "Authorization")
let uelSession = URLSession.shared.dataTask(with: url) { data, _, _ in
do {
let dataModel = try JSONDecoder().decode([model].self, from: data!)
print(dataModel)
DispatchQueue.main.async {
self.modelBib = dataModel
}
} catch _ {
}
}
uelSession.resume()
}
}
try using this (in addition to vadian comment):
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
Related
I am able to parse and decode data coming from IMGUR website. However when I try to print out one of the properties from Data it doesn’t show anything. How do I fix this? Also I want to access the contents of images, specifically the links. How can I access the contents Of the image since it’s an array?
struct PhotoResponse:Codable {
let success: Bool
let status: Int
let data: [Data]
}
struct Data:Codable {
let id: String
let title: String
let views: Int
let link: String
let images: [Image]?
let animated: Bool?
}
struct Image: Codable {
let id: String
let imageDescription: String?
let link: String?
let size: Int
}
class NetworkService{
static let shared = NetworkService()
private let baseURL = "https://api.imgur.com/3/gallery"
private init() {}
func getJSON( searchName: String, completion: #escaping([Data]) -> Void){
let endPoints = baseURL + "/search/time/week/?q=\(searchName)"
guard let url = URL(string: endPoints ) else{
return
}
var request = URLRequest(url: url)
let headers = ["Authorization": ""]
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Failed to query database", error)
}
guard let data = data else {
print("Data not received\(String(describing: error))")
return
}
let decoder = JSONDecoder()
do{
let decodedJson = try decoder.decode(PhotoResponse.self, from: data)
DispatchQueue.main.async {
completion(decodedJson.data)
}
}catch let error{
print("Json failed to decode\(String(describing: error))")
return
}
}.resume()
}
}
NetworkService.shared.getJSON(searchName: "cat") { (photos) in
for photo in photos {
print(photo.title)
print(photo.id)
}
Swift already has a Data struct, try renaming yours to something else, like MyData. Do the same with Image.
I am very new to Swift & XCode, after following several tutorials, I have made an MVVM architecture with an API service, however I could not pass my variable from ViewModel to my API service. I want to pass var user & pass from LoginViewModel to APIEndpoint
LoginViewModel
class LoginViewModel: ObservableObject, LoginService {
// I want to send this 2 variables to APIEndpoint
#Published var user = ""
#Published var pass = ""
var cancellables = Set<AnyCancellable>()
init(apiSession: APIService = APISession()) {
self.apiSession = apiSession
}
func login() {
let cancellable = self.login()
.sink(receiveCompletion: { result in
switch result {
case .failure(let error):
print("Handle error: \(error)")
case .finished:
break
}
}) { (detail) in
print(detail)
}
cancellables.insert(cancellable)
}
}
APIEndpoint
enum APIEndpoint {
case userLogin
case menuList
}
extension APIEndpoint: RequestBuilder {
var urlRequest: URLRequest {
switch self {
case .userLogin:
guard let url = URL(string: "https://jcouserapidev.oxxo.co.id/home/app")
else {preconditionFailure("Invalid URL format")}
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(Constants.API_TOKEN, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
// I want to pass the variables here, how??
let body: [String: Any] = ["user": $user, "pass": $pass]
let rb = try! JSONSerialization.data(withJSONObject: body)
request.httpBody = rb
return request
case .menuList:
guard let url = URL(string: "https://jcouserapidev.oxxo.co.id/home/app")
else {preconditionFailure("Invalid URL format")}
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(Constants.API_TOKEN, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
return request
}
}
}
RequestBuilder
protocol RequestBuilder {
var urlRequest: URLRequest {get}
}
LoginService
protocol LoginService {
var apiSession: APIService {get}
func login() -> AnyPublisher<LoginAPIResponse, APIError>
}
extension LoginService {
func login() -> AnyPublisher<LoginAPIResponse, APIError> {
return apiSession.request(with: APIEndpoint.userLogin)
.eraseToAnyPublisher()
}
}
APIService
protocol APIService {
func request<T: Decodable>(with builder: RequestBuilder, test: String) -> AnyPublisher<T, APIError>
}
APISession
struct APISession: APIService {
func request<T>(with builder: RequestBuilder) -> AnyPublisher<T, APIError> where T: Decodable {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
return URLSession.shared
.dataTaskPublisher(for: builder.urlRequest)
.receive(on: DispatchQueue.main)
.mapError { _ in .unknown }
.flatMap { data, response -> AnyPublisher<T, APIError> in
if let response = response as? HTTPURLResponse {
if (200...299).contains(response.statusCode) {
print(String(data: data, encoding: .utf8) ?? "")
return Just(data)
.decode(type: T.self, decoder: decoder)
.mapError {_ in .decodingError}
.eraseToAnyPublisher()
} else {
return Fail(error: APIError.httpError(response.statusCode))
.eraseToAnyPublisher()
}
}
return Fail(error: APIError.unknown)
.eraseToAnyPublisher()
}
.eraseToAnyPublisher()
}
}
Thank you all in advance.
You should change your enum in this form:
enum APIEndpoint {
case userLogin(user: String, password: String)
case menuList
}
change your requestBuilder:
extension APIEndpoint: RequestBuilder {
var urlRequest: URLRequest {
switch self {
case .userLogin(let user, let password):
guard let url = URL(string: "https://jcouserapidev.oxxo.co.id/home/app")
else {preconditionFailure("Invalid URL format")}
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(Constants.API_TOKEN, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
let body: [String: Any] = ["user": user, "pass": pass]
let rb = try! JSONSerialization.data(withJSONObject: body)
request.httpBody = rb
return request
case .menuList:
guard let url = URL(string: "https://jcouserapidev.oxxo.co.id/home/app")
else {preconditionFailure("Invalid URL format")}
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(Constants.API_TOKEN, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
return request
}
}
}
after this, in all login function you should pass user and password as parameter
Getting exception *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (__SwiftValue)' while trying to encode this Swift object to JSON. All non-optional members, objects Codable. What is the right way to encode or should use some 3rd party library?
struct MediaItem: Codable {
var key: String = ""
var filename: String = ""
}
struct NoteTask: Codable {
var id: String = ""
var notes: String = ""
var mediaList: [MediaItem] = []
}
static func addTask(task: NoteTask, callback: #escaping TaskAPICallback) {
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration)
let url = URL(string: postUrl)
var request : URLRequest = URLRequest(url: url!)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let params: [String: Codable?] = [
"email": task.id,
"notes": task.notes,
"fileList": task.fileList
]
do {
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: [])
} catch {
DispatchQueue.main.async {
callback(false)
}
return
}
...
}
The issue is that you're using JSONSerialization instead of JSONEncoder. JSONSerialization is the older, Foundation/Objective-C way of writing objects to JSON. It will only work with Foundation objects (see the documentation for a complete list).
Instead, you should use JSONEncoder. The tricky part is that JSONEncoder can't directly encode a Dictionary without some work on your part. There are a few ways to solve this, but if this is the only JSON format you're going to use, I'd probably just create custom keys for your structs using CodingKeys.
struct MediaItem: Codable {
var key: String = ""
var filename: String = ""
}
struct NoteTask: Codable {
var id: String = ""
var notes: String = ""
var mediaList: [MediaItem] = []
enum CodingKeys: String, CodingKey {
case id = "email"
case notes = "notes"
case mediaList = "fileList"
}
}
static func addTask(task: NoteTask, callback: #escaping TaskAPICallback) {
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration)
let url = URL(string: postUrl)
var request : URLRequest = URLRequest(url: url!)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
do {
request.httpBody = try JSONEncoder().encode(task)
} catch {
DispatchQueue.main.async {
callback(false)
}
return
}
}
I want to append another dictionary as a parameter to httpBody of URLRequest
Request Model:
struct RequestModel: Encodable {
let body: Body
}
struct Body: Encodable {
let name: String
let score: String
let favList: [String]
}
Api Request:
do {
var urlRequest = URLRequest(url: resourceURL)
urlRequest.httpMethod = kHTTPMethodPOST
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.httpBody = try JSONEncoder().encode(self.requestModel)
let dataTask = URLSession.shared.dataTask(with: urlRequest) { data, response, error in
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200,
let jsonData = data else {
completion(.failure(.responseError))
return
}
}
dataTask.resume()
} catch {
completion(.failure(.unknownError))
}
Another dictionary: airports
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
trying to append airports dictionary parameter to URLRequest but can't append.
Appreciate your help and suggestion!
Thanks
If you have to append the airports dictionary to the request body, you may want to include it in the Request model itself.
I would suggest updating your RequestModel and make it Encodable.
And include your airports dict as a part of your RequestModel
Something like this
struct RequestModel: Encodable {
let body: Body
let airportsDict: [String:String]
}
struct Body: Encodable {
let name: String
let score: String
let favList: [String]
}
This way your httpBody will have all the data you want to pass.
Hope this helps
The usual syntax to POST JSON is
do {
var urlRequest = URLRequest(url: resourceURL)
urlRequest.httpMethod = "POST"
let postData = try JSONEncoder().encode(self.requestModel)
urlRequest.httpBody = postData
urlRequest.setValue("\(postData.count)", forHTTPHeaderField:"Content-Length")
urlRequest.setValue("application/json", forHTTPHeaderField:"Accept")
urlRequest.setValue("application/json", forHTTPHeaderField:"Content-Type")
}
I have an error running my code. I need to represent whole information of my data requested from the URL.
But this breaks when I run.
I think the code is well done, but I don't know why this breaks when I run the app.
Probably have some error when threats the JSON.
This error:
Thread 3: Fatal error: Unexpectedly found nil while unwrapping an Optional value
import Foundation
public class UnidadeCurricularManager{
private var ucs = [UnidadeCurricular]();
init(){
//URL
let url = URL(string: "http://209.97.133.56/api/ucs")!
let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjQ2Yjg2ZDNlZDI2Y2IwOGU2NDFhZTI3NjNmMWI0ZDEwODAwZWI0M2U4YjM5MThiMTQ0YmU5YWFjMzBhNGU1ZDdhMTI4ZjA1MDI2NGNkYWZhIn0.eyJhdWQiOiIyIiwianRpIjoiNDZiODZkM2VkMjZjYjA4ZTY0MWFlMjc2M2YxYjRkMTA4MDBlYjQzZThiMzkxOGIxNDRiZTlhYWMzMGE0ZTVkN2ExMjhmMDUwMjY0Y2RhZmEiLCJpYXQiOjE1NTgzNDQ1MDIsIm5iZiI6MTU1ODM0NDUwMiwiZXhwIjoxNTg5OTY2OTAyLCJzdWIiOiIzIiwic2NvcGVzIjpbXX0.LSsn172WUQqEzUf3wzq4lxgBL8pbKGqjJCpn0iEFPFQY6DhZCtcm4jHkqTC0FFMYrAA1n87LfdBeSvcdgWFsndD6MoKHFkZViqZXlUHDeyMmT-bVs2IrNSE9kGuaRQhz1rtys2KFbB2y4lq5w2BPhokPYvLc0nTwZ7oPTZKQlJkUi80PKDMP3LMUQpilc2cSE8FGe-d1UtMYUeseivwHcNee4knjfOUIsGl7_pV4knU6DYTWL8IMXfb3GjbBTagFRWfbjeqMMvtFVdZGfTxdeVoMqSgEQlA0W20GyJ3Ox4WuZAaODk4b7Q4cudR8vmPTSjvVU-IqB6_9wvtE3HUMEwiGazQRcmFtVqBYFPVIBHFWNBsWI2AbMxR_KSA6URzF-6qydj53yRqO41E88KQiWbHy29mb8BCoNvjR4gN9F97rE9j9Xpt-EsHK6QEqBOeoJixu8srDrgmYul4nWroRU6dQsFZjfZS4Vnm1LFF-ykOo0YVY08oRcV3LQTb8TsnS3RuQzlMifEhDajBPTsVyCyW9OkkTsi3N96E1VeRhyT0S08InczXeRV_K5BMdt7tvVAEMPoR4GCcHAR5e7924WVsbl9KmJ4ituf_FdCfBKdvcmErURIlCfZRELLC_8kNaT-04CG3Vj9_LrUb6eOcJrutawh60V_ITojWAxyF2LnQ"
var request = URLRequest(url: url)
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpMethod = "GET"
URLSession.shared.dataTask(with: request) { (data, response , error) in
guard let data = data else {
return
}
do {
if let jsonDictionary = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? Dictionary<String,Any>
{
if let dataArray = jsonDictionary["data"] as? [[String:Any]] {
for data in dataArray {
let ucIdMapSiges = data["unidadeCurricularIdMapSiges"] as! Int
let ucNome = data["unidadeCurricularNome"] as! String
let ucSigla = data["unidadeCurricularAbreviatura"] as! String
let anoCurricularIdMapSiges = data["anoCurricularIdMapSiges"] as! Int
let periodoNome = data["unidadeCurricularAbreviatura"] as! String
let codigoEstudante = data["numeroEstudante"] as! String
let ects = data["numero_creditos"] as! Int
var uc = UnidadeCurricular (ucName: ucNome, ucSigla: ucSigla, ucIdMapSiges: ucIdMapSiges, anoCurricularIdMapSiges: anoCurricularIdMapSiges, periodoNome: periodoNome, codigoEstudante: codigoEstudante, ects: ects)
self.ucs.append(uc);
}
}
} else {
print("bad json")
}
} catch let error as NSError {
print(error)
}
}.resume()
}
func getUcs() -> Dictionary<String, [UnidadeCurricular]> {
var listaOfUcs = [String : [UnidadeCurricular]]()
for u in ucs{
if listaOfUcs[String(u.anoCurricularIdMapSiges)] != nil {
listaOfUcs[String(u.anoCurricularIdMapSiges)]!.append(u);
} else {
var ucName = [UnidadeCurricular]();
ucName.append(u);
listaOfUcs[String(u.anoCurricularIdMapSiges)] = ucName;
}
}
return listaOfUcs;
}
}
You cast
let codigoEstudante = data["numeroEstudante"] as! String
but it should be
let codigoEstudante = data["numeroEstudante"] as! Int
A better approach
do {
let res = try JSONDecoder().decode(Root.self, from: data)
print(res.data)
} catch {
print(error)
}
struct Root : Codable {
let data:[Model]
}
struct Model : Codable {
let unidadeCurricularIdMapSiges,anoCurricularIdMapSiges,numeroEstudante,numero_creditos:Int
let unidadeCurricularNome,unidadeCurricularAbreviatura:String
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let ff = UnidadeCurricularManager()
ff.getData { (res) in
print(res)
// refresh the table here
}
}
}
public class UnidadeCurricularManager{
func getData(completion:#escaping ([String:[Model]]) -> ()) {
let url = URL(string: "http://209.97.133.56/api/ucs")!
let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjQ2Yjg2ZDNlZDI2Y2IwOGU2NDFhZTI3NjNmMWI0ZDEwODAwZWI0M2U4YjM5MThiMTQ0YmU5YWFjMzBhNGU1ZDdhMTI4ZjA1MDI2NGNkYWZhIn0.eyJhdWQiOiIyIiwianRpIjoiNDZiODZkM2VkMjZjYjA4ZTY0MWFlMjc2M2YxYjRkMTA4MDBlYjQzZThiMzkxOGIxNDRiZTlhYWMzMGE0ZTVkN2ExMjhmMDUwMjY0Y2RhZmEiLCJpYXQiOjE1NTgzNDQ1MDIsIm5iZiI6MTU1ODM0NDUwMiwiZXhwIjoxNTg5OTY2OTAyLCJzdWIiOiIzIiwic2NvcGVzIjpbXX0.LSsn172WUQqEzUf3wzq4lxgBL8pbKGqjJCpn0iEFPFQY6DhZCtcm4jHkqTC0FFMYrAA1n87LfdBeSvcdgWFsndD6MoKHFkZViqZXlUHDeyMmT-bVs2IrNSE9kGuaRQhz1rtys2KFbB2y4lq5w2BPhokPYvLc0nTwZ7oPTZKQlJkUi80PKDMP3LMUQpilc2cSE8FGe-d1UtMYUeseivwHcNee4knjfOUIsGl7_pV4knU6DYTWL8IMXfb3GjbBTagFRWfbjeqMMvtFVdZGfTxdeVoMqSgEQlA0W20GyJ3Ox4WuZAaODk4b7Q4cudR8vmPTSjvVU-IqB6_9wvtE3HUMEwiGazQRcmFtVqBYFPVIBHFWNBsWI2AbMxR_KSA6URzF-6qydj53yRqO41E88KQiWbHy29mb8BCoNvjR4gN9F97rE9j9Xpt-EsHK6QEqBOeoJixu8srDrgmYul4nWroRU6dQsFZjfZS4Vnm1LFF-ykOo0YVY08oRcV3LQTb8TsnS3RuQzlMifEhDajBPTsVyCyW9OkkTsi3N96E1VeRhyT0S08InczXeRV_K5BMdt7tvVAEMPoR4GCcHAR5e7924WVsbl9KmJ4ituf_FdCfBKdvcmErURIlCfZRELLC_8kNaT-04CG3Vj9_LrUb6eOcJrutawh60V_ITojWAxyF2LnQ"
var request = URLRequest(url: url)
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpMethod = "GET"
URLSession.shared.dataTask(with: request) { (data, response , error) in
guard let data = data else {
return
}
// print(String(data:data,encoding: .utf8))
do {
let res = try JSONDecoder().decode(Root.self, from: data)
let dic = Dictionary(grouping: res.data, by: { String($0.anoCurricularIdMapSiges) })
completion(dic)
} catch let error as NSError {
print(error)
}
}.resume()
}
}
struct Root : Codable {
let data:[Model]
}
struct Model : Codable {
let unidadeCurricularIdMapSiges,anoCurricularIdMapSiges,numeroEstudante,numero_creditos:Int
let unidadeCurricularNome,unidadeCurricularAbreviatura:String
}