LoopBack + iOS, Getting started (read Data)!

LoopBack + iOS,  Getting started (read Data)!

Un petit Tuto rapide, depuis un moment je souhaitais reprendre le Dev iOS. Cela fait 3 4 ans que je ne m'y étais pas replongé réellement. Depuis, les technologies ont évolué, le Dev iOS et la publiciation d'applications ont été simplifiés, Swift est arrivé, NodeJS et AngularJS ...

Nous allons donc tenter de rassembler un peu tout ca. Réaliser un serveur NodeJS, qui sera interrogé par une application iOS Objtective-C (exemple en swift disponible sur Github). L'application iOS prendra en compte l'Universal Storyboard.


I/ Un serveur NodeJs

Pour commencer, il s'agit ici de créer un serveur NodeJS fournissant une API que l'application pourra interroger. Nous parlons de web service REST API. Plusieurs packages NPM permette de réaliser facilement ce genre de choses.

Je n'en ai pas testé d'autres pour le moment.

Ces packages permettent en quelques lignes de commande de générer une base d'application NodeJS MongoDB (ou autre). L'architecture, les modèles, les controllers ... toutes sortes de templates pourront être faits en quelques secondes. Bien que l'on aime parfois tout faire à la main ;)! C'est parfois pratique et cela permet un certain gain de temps.

Ici, nous utiliserons LoopBack.

Installer LoopBack

Npm doit être installé sur votre machine. Il faut commencer par installer LoopBack, cela peut prendre un certain temps :

npm install -g strongloop

Après un bon moment tout sera installé. Pour ceux qui ne sont pas assez patients, voici la justification du temps d'installation :

├── sl-blip@1.0.0
├── which@1.0.9
├── ini@1.3.3
├── async@0.9.0
├── read@1.0.5 (mute-stream@0.0.4)
├── nopt@3.0.1 (abbrev@1.0.5)
├── colors@1.0.3
├── debug@2.1.3 (ms@0.7.0)
├── optimist@0.6.1 (wordwrap@0.0.2, minimist@0.0.10)
├── nodefly-register@0.3.3
├── strong-start@1.0.3 (osenv@0.1.0, posix-getopt@1.1.0, lodash@3.7.0)
├── is2@0.0.13 (deep-is@0.1.2)
├── json-file-plus@2.0.0 (is@2.0.2, node.extend@1.1.3, promiseback@2.0.1)
├── fs.extra@1.2.1 (mkdirp@0.3.5, fs-extra@0.6.4, walk@2.2.1)
├── strong-build@1.0.3 (posix-getopt@1.1.0, shelljs@0.3.0, json-file-plus@1.0.7, lodash@2.4.1, vasync@1.6.3)
├── prompt@0.2.14 (revalidator@0.1.8, pkginfo@0.3.0, winston@0.8.3, utile@0.2.1)
├── strong-agent@1.4.0 (semver@2.2.1, strong-license@1.0.2)
├── strong-registry@1.1.4 (osenv@0.0.3, semver@2.3.2, bluebird@1.2.4, commander@2.8.0, rimraf@2.3.2, inquirer@0.4.1)
├── strong-deploy@1.2.0 (strong-url-defaults@1.0.0, posix-getopt@1.1.0, shelljs@0.3.0, concat-stream@1.4.8, strong-tunnel@1.1.1)
├── node-inspector@0.7.4 (opener@1.3.0, debug@0.8.1, async@0.8.0, yargs@1.2.6, strong-data-uri@0.1.1, rc@0.3.5, glob@3.2.11, ws@0.4.32, express@4.0.0)
├── loopback-sdk-angular-cli@1.1.4 (semver@2.3.2, loopback-sdk-angular@1.3.7, docular@0.6.6, express@3.20.2)
├── strong-mesh-models@5.0.3 (user-home@1.1.1, sprintf@0.1.5, osenv@0.1.0, strong-url-defaults@1.0.0, posix-getopt@1.1.0, serve-favicon@2.2.0, concat-stream@1.4.8, compression@1.4.3, errorhandler@1.3.5, lodash@3.7.0, strong-tunnel@1.1.1, loopback-boot@2.7.0, request@2.55.0, loopback-datasource-juggler@2.25.1, minkelite@1.0.0, loopback-explorer@1.7.2, loopback@2.16.3, strong-npm-ls@1.0.5)
├── strong-pm@3.1.9 (uid-number@0.0.5, chownr@0.0.1, osenv@0.1.0, npm-path@1.0.1, strong-url-defaults@1.0.0, posix-getopt@1.1.0, extsprintf@1.3.0, mkdirp@0.5.0, passwd-user@1.1.1, bl@0.9.4, concat-stream@1.4.8, serve-favicon@2.2.0, strong-service-install@1.1.2, errorhandler@1.3.5, compression@1.4.3, strong-control-channel@1.1.2, express@4.12.3, lodash@2.4.1, tar@1.0.3, strong-tunnel@1.1.1, strong-fork-cicada@1.1.2, http-auth@2.2.5, strong-npm-ls@1.0.5)
├── strong-supervisor@1.5.1 (dotenv@0.2.8, posix-getopt@1.1.0, heapdump@0.3.5, strong-fork-syslog@1.2.3, strong-control-channel@1.1.2, strong-cluster-control@2.0.1, strong-log-transformer@1.0.1, strong-statsd@2.0.2, strong-trace@1.2.0, strong-npm-ls@1.0.5)
├── generator-loopback@1.9.0 (inflection@1.7.0, chalk@0.5.1, yosay@1.0.3, request@2.55.0, loopback-swagger@2.0.0, yeoman-generator@0.18.10, loopback-workspace@3.10.1)
└── strong-arc@1.1.0 (opener@1.4.1, cookie-parser@1.3.4, split@0.3.3, serve-favicon@2.2.0, errorhandler@1.2.4, http-proxy@1.10.1, fs-extra@0.14.0, ws@0.4.32, request@2.55.0, loopback-boot@2.7.0, loopback-datasource-juggler@2.25.1, express-jsxtransform@1.1.0, express@4.8.8, loopback@2.16.3, loopback-workspace@3.10.1, strong-pm@1.7.3, strong-mesh-client@1.4.0)

Créer son projet

Une fois cela fait, nous allons créer l'application Node.

slc loopback
[?] Enter a directory name where to create the project: waos-NodeIos
[?] What's the name of your application? waos-NodeIos

Nous allons maintenant créer un model de données nommé person, et lui ajouter deux propriétés, firstname and mail

cd waos-NodeIos
slc loopback:model
? Enter the model name: person
? Select the data-source to attach person to: db (memory)
? Select model's base class: PersistedModel
? Expose person via the REST API? Yes
? Custom plural form (used to build REST URL): people
Let's add some person properties now.

Enter an empty property name when done.
? Property name: firstname
   invoke   loopback:property
? Property type: string
? Required? Yes

Let's add another person property.
Enter an empty property name when done.
? Property name: mail
   invoke   loopback:property
? Property type: string
? Required? Yes

Let's add another person property.
Enter an empty property name when done.
? Property name: 

Maintenant, lancer le serveur

node .

ou

slc run

Votre api doit être disponible sur le port 3000 de votre machine. Afin de le vérifier, rendez vous à l'adresse suivant : http://localhost:3000

vous devriez avoir un message de ce genre : {"started":"2015-04-18T20:34:31.489Z","uptime":616.44}

Vous pouvez alors accéder à l'explorer de loopback : http://localhost:3000/explorer

Insérer des données

De base, l'insertion avec LoopBack n'est pas persistante. Si nous souhaitons que nos POST, sur l'API soient conservés, même après un redémarrage de l'application, nous devons le préciser. Plusieurs solutions s'offrent à nous. En voici une, MongoDB.

  • MongoDB, il doit donc être installé sur votre machine.

    Installons le connecteur :

      npm install loopback-connector-mongodb --save
    

    modifions le fichier adéquat : waos-NodeIos/server/datasources.json

      {
        "db": {
          "name": "db",
          "connector": "mongodb"
        }
      }
    

Une fois la persistance des données mise en place, nous pouvons en insérer. Il faut se rendre sur l'explorer, http://localhost:3000/explorer .

A cette adresse est disponible l'ensemble des méthodes de votre API, auxquels il est possible de faire appel.

Soit pour notre model Person :

model Person

Plutôt couwl non ? ;)

Bien nous allons simplement utilister la méthode post / people. Il suffit de cliquer dessus, et d'insérer une donnée comme ceci :

insert one person

Cliquer alors sur Try i out!. Si tout se passe bien vous aurez une réponse en 200. Vous pourrez vérifier que l'insertion a fonctionné en allant faire un tour du coté de get / people.

Get person

Tout est terminé, votre API tourne, nous pouvons donc passer à l'application IOS :).

Github server node (LoopBack)

Vous pouvez retrouver le code du serveur sur Github ici :).


II/ L'application iOS

Du coté de l'application iOS, nous n'allons pas rentrer dans le détail du code, libre a chacun d'approfondir. Seul les sections les plus importantes sont présentées ci-dessous.

Présentation du code

Importer LoopBack

#import <LoopBack/LoopBack.h>

Déclarations

@interface ViewController ()
@property (strong, nonatomic) LBRESTAdapter *adapter;
@property (strong, nonatomic) NSMutableArray *tableData;
@property (weak, nonatomic) IBOutlet UITableView *myTable;
@end

Initialiser la connexion à l'API

- (LBRESTAdapter *) adapter
{
    if( !_adapter)
        _adapter = [LBRESTAdapter adapterWithURL:[NSURL URLWithString:@"http://localhost:3000/api"]];
    return _adapter;
}

Reqêter sur l'API

/*************************************************/
// Functions
/*************************************************/
- (void) getSomething {

    void (^loadSuccessBlock)(NSArray *) = ^(NSArray *models) {
        NSLog( @"selfSuccessBlock %lu", models.count);
        NSLog(@"Success on Static Method result: %@", models);

        [self.tableData removeAllObjects ];

        for (int i = 0; i < models.count; i++) {
            LBModel *modelInstance = (LBModel*)[models objectAtIndex:i];
            [self.tableData addObject:modelInstance ];
        }

        [self.myTable reloadData];
    };
    void (^loadErrorBlock)(NSError *) = ^(NSError *error) {
        NSLog( @"Error %@", error.description);
    };


    LBModelRepository *prototype = [ [self adapter]  repositoryWithModelName:@"Something"];
    [prototype allWithSuccess: loadSuccessBlock failure: loadErrorBlock];

};

Afficher les données

- (NSMutableArray *) tableData
{
    if ( !_tableData) _tableData = [[NSMutableArray alloc] init];
    return _tableData;
};

/*************************************************/
// Main
/*************************************************/

// Table View
/**************************************/
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    static NSString *simpleTableIdentifier = @"SimpleTableItem";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
    }

    LBModel *model = (LBModel *)[self.tableData objectAtIndex:indexPath.row];
    cell.textLabel.text = [[NSString alloc] initWithFormat:@"%@ - %@", [model objectForKeyedSubscript:@"firstname"] ,[model objectForKeyedSubscript:@"mail"]  ];

    return cell;
}

Github client iOS

Vous pouvez retrouver le code du client Objective-C sur Github ici :).
Version Swift ici :)


En espérant en avoir aidé certains dans leurs projets iOS. J'essayerais de maintenir les projets GitHub à jour avec les Maj Apple.


Edit (26/04/2015) Ce Tuto appartient à la série suivante :