# iOS app
COYLA
J Carlos
DWM
Sources doc: https://hackmd.io/@sensei/r1Ep-cw8r
Github mobile: https://github.com/blade-sensei/ios-app-estiam
## API projects
On met en place une API qui permet de récupérer des users - projects - détails d'un projets et la modification d'un projet précis.
### Connection base de données et run du server
```javascript=
// config server
const port = process.env.PORT || config.server.port;
app.listen(port, () => {
logger.info(`server api is running on : ${port} port ...`);
});
// config database
const mongoURI = process.env.DB_URI || config.db.uri;
mongoose
.connect(mongoURI)
.then(() => {
return logger.info(`database connection on ${mongoose.connection.port} port with success!`);
})
.catch((error) => {
logger.info('fail to connect to database');
logger.error(error.message);
});
```
### Routes
```javascript=
const router = express.Router();
router.use('/users', userController);
router.use('/auth', authController);
router.use('/projects', projectController);
module.exports = router;
```
### Route projects
Voici un example d'une route qui récupère les projets. Avant de requeter la base de données on vérifie que l'utilisateur envoie un token
```javascript=
router.get('',
token.verifyToken,
async (req, res) => {
try {
const projects = await projectService.findAll();
res.send(projects);
} catch (e) {
logger.info(e.message);
return res.status(500).send('not found');
}
});
```
### Test
Voici le résultat d'un test avec l'interface swagger
`API: localhost/api/projects`

## App iOS Swift
### Creation des écrans
- Sur Xcode on va créer une application simple
- Ensuite on crée quelques écrans pour la liste de projets et détails
- On oublie pas de rajouter également un Navigation Controller pour naviger entre chaque écran
- Sachant que la view pour lister les projets et une view du type TableView
- On rajoute une view "Home" et on déclare que la navigation commence par cette view "Home"

### Récupération des données sur une API
Pour cette étape on a besoin de modifier la méthode "viewDidLoad" de notre TableViewController associé à la vue "Projects".
Cette méthode effecute le code AVANT de charger la vue.
```swift
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
tableView.tableFooterView = UIView(frame: CGRect.zero)
let projectsURL = URL(string: "http://localhost:3000/api/projects")!
let task = URLSession.shared.dataTask(with: projectsURL) { (data, response, error) in
guard let data = data else { return }
do {
let projects = try JSONSerialization.jsonObject(with: data, options: [])
print(projects)
} catch {
print(error)
}
}.resume()
}
```
:::info
On print dans le console juste pour tester la réponse que l'API nous renvoie
:::

Pour le moment c'est normal. On n'envoie pas de token à l'API
## Retrieve token/login
On va faire une requete vers la route auth/login pour récuperer le token.
On récupère le texte des champs username et password pour les mettre dans notre body de requete.
Ensuite on a besoin de créer un model/struct Auth qui va mapper ou Parser la réponse json en object swift
Dès qu'on récupère le token il faut qu'on le stock quelque part pour qu'on l'envoie dans les prochaines requetes
```swift
@IBAction func login(_ sender: Any) {
let username = textFieldUsername.text
let password = textFieldPassword.text
let parametersRequestLogin = ["username": username, "password": password]
let projectsURL = URL(string: "http://localhost:3000/api/auth/login")!
var request = URLRequest(url: projectsURL)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parametersRequestLogin, options: []) else { return }
request.httpBody = httpBody
let session = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else { return }
do {
let auth:Auth?
let decode = JSONDecoder()
let authResponse = try decode.decode(Auth.self, from: data)
print(authResponse.token)
UserDefaults.standard.set(authResponse.token, forKey: "userToken" )
} catch {
print(error)
}
}.resume()
}
```
## Liste et details
Lorsqu'on charge la view pour afficher la liste de projets on va faire une requette vrs l'API
On oublie pas de récupérer notre token dans UserDefaults
```swift
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
tableView.tableFooterView = UIView(frame: CGRect.zero)
let projectsURL = URL(string: "http://localhost:3000/api/projects")!
var request = URLRequest(url: projectsURL)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let tokenUser = UserDefaults.standard.string(forKey: "userToken") ?? ""
request.addValue(tokenUser, forHTTPHeaderField: "x-access-token")
let session = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else { return }
let decode = JSONDecoder()
self.projects = try! decode.decode([Project].self, from: data)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}.resume()
}
```
On va passer le projet à la vue details, pour cela il faut changer la méthode prepare qui prépare les données vers la prochaine navigation.
```swift
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Project" {
guard let selectedContactRow = tableView.indexPathForSelectedRow?.row else { return }
guard let detaislViewController = segue.destination as? DetailsViewController else { return }
let project = projects[selectedContactRow]
detaislViewController.project = project
}
}
```
Ensuite dans notre vue details on va utiliser l'object project qui a été passé la vue Table, et on va changer le titre de notre vue ainsi que mettre une description/status du projet sur cette page.
```swift
var project: Project? {
didSet {
self.title = self.project?.title
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.descriptionLabel.text = self.project?.description
// Do any additional setup after loading the view.
}
```
## Résultat
Vue projects

Vue détails

## Test
Pour que vous puissiez tester
### API Server
- Créer un base de données mongo appelé "dev" en local
- Lancez le serveur de db
- Taper la commande suivante pour installer les dépendances
```bash
npm install
```
- Lancer le serveur API avec la commande:
```
npm run start:dev
npm run start
```
- Créer les jeux de données, taper les urls
- http://localhost:3000/seed/users
- http://localhost:3000/seed/projects

- Vous pouvez tester l'API en utilisant le swagger
- taper l'url: http://localhost:3000/explorer/#/
- Utiliser la route auth/login, click sur le bouton "try it out"
- username = demo et password = demo
- Récupérer (copiez) les token de la réponse
- Click sur Authorize et rentrez copier le token
- Vous pouvez maintenant accéder aux autres routes
### Mobile iOS
Ouvrir le projet sur XCODE
Appuyer sur CMD + R
Le projet va se lancer, vous arriverez sur une page de login. Rentrez: username: demo et password: demo.