Send push notifications in a social network iOS app - Part 1: Build the backend
Tags: pusher, ios, swift, node
Published: 2018-11-19 17:14:21

---
title: Send push notifications in a social network iOS app - Part 1: Build the backend
published: true
description: 
tags: pusher, ios, swift, node.js
---
> To follow this tutorial you will need a Mac with Xcode installed, and knowledge of Xcode and Swift. You'll also need basic knowledge of PHP (including the Laravel framework), a Pusher account, and Cocoapods installed on your machine.

Push notifications are a great way to engage users of your application. It lets you send notifications when certain events happen on your service. This can lead to re-engagement.

While building a social network app, you'll need to send push notifications to your users. These notifications will help users know when certain events happen in your application. For instance, you can send push notifications to a user when someone comments on their photo.

As powerful as push notifications are, they are a double-edged sword. Most users will uninstall your application if they feel like they are being spammed.

Over the course of two articles, we will see how we can build a social networking iOS application. We will add push notifications to the user when someone comments on a photo they uploaded. Then we'll add settings so users can specify when they want to receive notifications.

![](//images.ctfassets.net/1es3ne0caaid/51GgQzYiqQEMAQWOK8AMgS/fd0d5bb1bbaa7f1f198fed340d25cd53/ios-push-notifications-social-network-demo.gif)

## Prerequisites

To follow along in this tutorial you need to have the following:

- A Mac with [Xcode](https://developer.apple.com/xcode/) installed.
- Knowledge of using Xcode.
- Knowledge of the [Swift](https://developer.apple.com/swift/) programming language.
- Knowledge of PHP and [Laravel](https://laravel.com/docs/).
- [Laravel CLI](https://laravel.com/docs/5.6/installation) installed on your machine.
- SQLite installed on your machine. [See installation guide](http://www.sqlitetutorial.net/download-install-sqlite/).
- A Pusher beams API Key. [Create one here.](https://dash.pusher.com/authenticate/register?ref=pn-landing-page)
- Cocoapods installed on your machine. [See installation guide](https://guides.cocoapods.org/using/getting-started.html).

## Creating our Pusher application

> ⚠️ To use push notifications, you have to [be a part of the Apple Developer program](https://developer.apple.com/programs/enroll/). Also, push notifications do not work on simulators so you will need an actual iOS device to test.

Pusher [Beams](https://pusher.com/beams) has first-class support for native iOS applications. Your iOS app instances subscribe to **Interests**; then your servers send push notifications to those interests. Every app instance subscribed to that interest will receive the notification, even if the app is not open on the device at the time.

This section describes how you can set up an iOS app to receive transactional push notifications about news updates through Pusher.

### Configure APNs

Pusher relies on the Apple Push Notification service (APNs) to deliver push notifications to iOS application users on your behalf. When we deliver push notifications, we use your key that has APNs service enabled. This page guides you through the process of getting the key and how to provide it to Pusher.

Head over to the Apple Developer dashboard by clicking [here](https://developer.apple.com/account) and then create a new key as seen below:

![](//images.ctfassets.net/1es3ne0caaid/3XWdqEhwo8AuGKIywEsC6s/b260c8ac1052beceb634e1dcbeb99c6f/ios-push-notifications-social-network-create-APN.gif)

When you have created the key, download it. Keep it safe as we will need it in the next section.

> ⚠️ You have to keep the generated key safe as you cannot get it back if you lose it.

### Creating your Pusher application

The next thing you need to do is create a new Pusher Beams application from the [Pusher dashboard](https://dash.pusher.com).

![](//images.ctfassets.net/1es3ne0caaid/2Af98mjyDGqUA8wMkgYyaU/9497179efc4643ae5c48e844b8644011/ios-push-notifications-social-network-create-beams.png)

When you have created the application, you should be presented with a quick start that will help you set up the application.

In order to configure your Beams instance, you will need to get the key with APNs service enabled by Apple. This is the same key as the one we downloaded in the previous section. Once you’ve got the key, upload it.

![](//images.ctfassets.net/1es3ne0caaid/1OvPaR9NrieciOQuWYuCCE/4059623254d3571bf71f5069a32904ad/ios-push-notifications-social-network-add-APN-to-beams.png)

Enter your Apple Team ID. You can get the Team ID from [here](https://developer.apple.com/account/#/membership). You can then continue with the setup wizard and copy the instance ID and secret key for your Pusher application.

## Building the backend

Before we start building the iOS application, let’s build the backend API using Laravel. To get started we need to set up our Laravel application. Run the command below using your terminal:

```
    $ Laravel new gram

```

This will create a new Laravel application in the `gram` directory.

### Configuring our database

Our application will need to connect to a database and we will be using SQLite as our database of choice as it's the easiest to set up.

To get started, create a new `database.sqlite` file in the `database` directory. Next open the `.env` file that comes with the Laravel project and replace the following lines:

```
    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=3306
    DB_DATABASE=homestead
    DB_USERNAME=homestead
    DB_PASSWORD=secret

```

With:

```
    DB_CONNECTION=sqlite
    DB_DATABASE=/full/path/to/database.sqlite

```

Now we have a connection to the database.

### Creating our migrations, models, and controllers

When you want to create a migration, model, and controller, you should use the command below:

```
    $ php artisan make:model ModelName -mc

```

Using the above command as a template, create the following models, migrations, and controllers:

- `Photo`
- `PhotoComment`
- `UserFollow`
- `UserSetting`

In that order.

After running the commands, we should have migrations in the `database/migrations` directory, models in the `app` directory, and controllers in the `app/Http/Controllers` directory.

Let’s update the migrations. Open the `*_create_photos_table.php` migration and replace the `up` method with the following:

```
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span><span class="hljs-params">()</span>
    </span>{
        Schema::create(<span class="hljs-string">'photos'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(Blueprint $table)</span> </span>{
            $table->increments(<span class="hljs-string">'id'</span>);
            $table->unsignedInteger(<span class="hljs-string">'user_id'</span>);
            $table->foreign(<span class="hljs-string">'user_id'</span>)->references(<span class="hljs-string">'id'</span>)->on(<span class="hljs-string">'users'</span>);
            $table->string(<span class="hljs-string">'image'</span>);
            $table->string(<span class="hljs-string">'image_path'</span>);
            $table->string(<span class="hljs-string">'caption'</span>)->nullable();
            $table->timestamps();
        });
    }
```

Open the `*_create_photo_comments_table.php` migration and replace the `up` method with the following:

```
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span><span class="hljs-params">()</span>
    </span>{
        Schema::create(<span class="hljs-string">'photo_comments'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(Blueprint $table)</span> </span>{
            $table->increments(<span class="hljs-string">'id'</span>);
            $table->unsignedInteger(<span class="hljs-string">'photo_id'</span>);
            $table->foreign(<span class="hljs-string">'photo_id'</span>)->references(<span class="hljs-string">'id'</span>)->on(<span class="hljs-string">'photos'</span>);
            $table->unsignedInteger(<span class="hljs-string">'user_id'</span>);
            $table->foreign(<span class="hljs-string">'user_id'</span>)->references(<span class="hljs-string">'id'</span>)->on(<span class="hljs-string">'users'</span>);
            $table->text(<span class="hljs-string">'comment'</span>);
            $table->timestamps();
        });
    }
```

Open the `*_create_user_follows_table.php` migration and replace the `up` method with the following:

```
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span><span class="hljs-params">()</span>
    </span>{
        Schema::create(<span class="hljs-string">'user_follows'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(Blueprint $table)</span> </span>{
            $table->increments(<span class="hljs-string">'id'</span>);
            $table->unsignedInteger(<span class="hljs-string">'follower_id'</span>);
            $table->foreign(<span class="hljs-string">'follower_id'</span>)->references(<span class="hljs-string">'id'</span>)->on(<span class="hljs-string">'users'</span>);
            $table->unsignedInteger(<span class="hljs-string">'following_id'</span>);
            $table->foreign(<span class="hljs-string">'following_id'</span>)->references(<span class="hljs-string">'id'</span>)->on(<span class="hljs-string">'users'</span>);
            $table->timestamps();
        });
    }
```

Open the `*_create_user_settings_table.php` migration and replace the `up` method with the following:

```
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span><span class="hljs-params">()</span>
    </span>{
        Schema::create(<span class="hljs-string">'user_settings'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(Blueprint $table)</span> </span>{
            $table->increments(<span class="hljs-string">'id'</span>);
            $table->unsignedInteger(<span class="hljs-string">'user_id'</span>);
            $table->foreign(<span class="hljs-string">'user_id'</span>)->references(<span class="hljs-string">'id'</span>)->on(<span class="hljs-string">'users'</span>);
            $table->enum(<span class="hljs-string">'notification_comments'</span>, [<span class="hljs-string">'Off'</span>, <span class="hljs-string">'Following'</span>, <span class="hljs-string">'Everyone'</span>])
                  ->default(<span class="hljs-string">'Following'</span>);
        });
    }
```

That’s all for the migrations. Execute the migrations by running the command below:

```
    $ php artisan migrate

```

When that’s done, we can update our models. Open the `Photo` model in the `app` directory and replace the contents with the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>;

    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Model</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Photo</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
    </span>{
        <span class="hljs-keyword">protected</span> $hidden = [<span class="hljs-string">'image_path'</span>];

        <span class="hljs-keyword">protected</span> $with = [<span class="hljs-string">'user'</span>, <span class="hljs-string">'comments'</span>];

        <span class="hljs-keyword">protected</span> $fillable = [<span class="hljs-string">'user_id'</span>, <span class="hljs-string">'caption'</span>, <span class="hljs-string">'image'</span>, <span class="hljs-string">'image_path'</span>];

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">user</span><span class="hljs-params">()</span>
        </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>->belongsTo(User::class);
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">comments</span><span class="hljs-params">()</span>
        </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>->hasMany(PhotoComment::class)->orderBy(<span class="hljs-string">'id'</span>, <span class="hljs-string">'desc'</span>);
        }
    }
```

In the model above we have the `user` and `comments` methods, which are relationships to the `User` model and the `PhotoComment` model.

Open the `PhotoComment` class in the `app` directory and replace the content with the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>;

    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Model</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Notifications</span>\<span class="hljs-title">Notifiable</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PhotoComment</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
    </span>{
        <span class="hljs-keyword">use</span> <span class="hljs-title">Notifiable</span>;

        <span class="hljs-keyword">protected</span> $with = [<span class="hljs-string">'user'</span>];

        <span class="hljs-keyword">protected</span> $fillable = [<span class="hljs-string">'photo_id'</span>, <span class="hljs-string">'user_id'</span>, <span class="hljs-string">'comment'</span>];

        <span class="hljs-keyword">protected</span> $casts = [<span class="hljs-string">'photo_id'</span> => <span class="hljs-string">'int'</span>, <span class="hljs-string">'user_id'</span> => <span class="hljs-string">'int'</span>];

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scopeForPhoto</span><span class="hljs-params">($query, int $id)</span>
        </span>{
            <span class="hljs-keyword">return</span> $query->where(<span class="hljs-string">'photo_id'</span>, $id);
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">user</span><span class="hljs-params">()</span>
        </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>->belongsTo(User::class);
        }
    }
```

In the model above we are using the `Notifiable` trait because we want to be able to send push notifications when new comments are made on photos later in the article. We also have a `scopeForPhoto` method, which is an [Eloquent query scope](https://laravel.com/docs/5.6/eloquent#query-scopes). We also have a `user` method, which is a relationship to the `User` model.

Open the `User` model in the `app` directory and replace the content with the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>;

    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Notifications</span>\<span class="hljs-title">Notifiable</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Foundation</span>\<span class="hljs-title">Auth</span>\<span class="hljs-title">User</span> <span class="hljs-title">as</span> <span class="hljs-title">Authenticatable</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Authenticatable</span>
    </span>{
        <span class="hljs-keyword">use</span> <span class="hljs-title">Notifiable</span>;

        <span class="hljs-keyword">protected</span> $fillable = [<span class="hljs-string">'name'</span>, <span class="hljs-string">'email'</span>, <span class="hljs-string">'password'</span>];

        <span class="hljs-keyword">protected</span> $hidden = [<span class="hljs-string">'password'</span>, <span class="hljs-string">'remember_token'</span>];

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">allowsCommentsNotifications</span><span class="hljs-params">(User $actor)</span>
        </span>{
            $status = strtolower(<span class="hljs-keyword">$this</span>->settings->notification_comments);

            <span class="hljs-keyword">switch</span> ($status) {
                <span class="hljs-keyword">case</span> <span class="hljs-string">'everyone'</span>: <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
                <span class="hljs-keyword">case</span> <span class="hljs-string">'following'</span>: <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>->isFollowing($actor);
                <span class="hljs-keyword">default</span>: <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
            }
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isFollowing</span><span class="hljs-params">(User $user)</span>: <span class="hljs-title">bool</span>
        </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>->following->where(<span class="hljs-string">'following_id'</span>, $user->id)->count() > <span class="hljs-number">0</span>;
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scopeOtherUsers</span><span class="hljs-params">($query)</span>
        </span>{
            <span class="hljs-keyword">return</span> $query->where(<span class="hljs-string">'id'</span>, <span class="hljs-string">'!='</span>, auth()->user()->id);
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">following</span><span class="hljs-params">()</span>
        </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>->hasMany(UserFollow::class, <span class="hljs-string">'follower_id'</span>);
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">followers</span><span class="hljs-params">()</span>
        </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>->hasMany(UserFollow::class, <span class="hljs-string">'following_id'</span>);
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">settings</span><span class="hljs-params">()</span>
        </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>->hasOne(UserSetting::class);
        }
    }
```

In the model above we have six methods:

- `allowsCommentsNotifications` checks to see if the owner of the photo has settings that permit notifications to be sent to them when there is a new comment.
- `isFollowing` checks if a user is following another user.
- `scopeOtherUsers` is an Eloquent query scope.
- `following`, `followers` and `settings` are methods that define relationships with other models.

Open the `UserFollow` model in the `app` directory and replace the content with the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>;

    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Model</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserFollow</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
    </span>{
        <span class="hljs-keyword">protected</span> $fillable = [<span class="hljs-string">'follower_id'</span>, <span class="hljs-string">'following_id'</span>];
    }
```

Finally, open the `UserSetting` model in the `app` directory and replace the content with the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>;

    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Model</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserSetting</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
    </span>{
        <span class="hljs-keyword">protected</span> $fillable = [<span class="hljs-string">'notification_comments'</span>];

        <span class="hljs-keyword">protected</span> $hidden = [<span class="hljs-string">'id'</span>, <span class="hljs-string">'user_id'</span>];

        <span class="hljs-keyword">public</span> $timestamps = <span class="hljs-keyword">false</span>;

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scopeForCurrentUser</span><span class="hljs-params">($query)</span>
        </span>{
            <span class="hljs-keyword">return</span> $query->where(<span class="hljs-string">'user_id'</span>, auth()->user()->id);
        }
    }
```

Above we have the `scopeForCurrentUser` method, which is an Eloquent query scope.

> We set the `$timestamps` property to false to instruct Eloquent not to attempt to automatically manage the `created_at` and `updated_at` fields as we do not have them in the user settings table.

One last thing we want to do is, create a new setting automatically when a user is created. For this, we will use an [Eloquent event](https://laravel.com/docs/5.6/eloquent#events). Open the `AppServiceProvider` class in the `app/Providers` directory and replace the boot method with the following:

```
    public function boot()
    {
        \App\User::created(function ($user) {
            $user->settings()->save(new \App\UserSetting);
        });
    }

```

As seen above, when a new user is created, a new user setting is saved to the user.

Next, let’s update the logic for the controllers. Open the `PhotoController.php` in the `app/Http/Controllers` directory and replace the contents with the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Controllers</span>;

    <span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Photo</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Request</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Facades</span>\<span class="hljs-title">Storage</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PhotoController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
    </span>{
        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span><span class="hljs-params">()</span>
        </span>{
            $photos = Photo::orderBy(<span class="hljs-string">'id'</span>, <span class="hljs-string">'desc'</span>)->paginate(<span class="hljs-number">20</span>);

            <span class="hljs-keyword">return</span> response()->json($photos->toArray());
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span><span class="hljs-params">(Request $request)</span>
        </span>{
            $data = $request->validate([
                <span class="hljs-string">'caption'</span> => <span class="hljs-string">'required|between:1,1000'</span>,
                <span class="hljs-string">'image'</span> => <span class="hljs-string">'required|image|mimes:jpeg,gif,png'</span>,
            ]);

            $path = Storage::disk(<span class="hljs-string">'public'</span>)->putFile(<span class="hljs-string">'photos'</span>, $request->file(<span class="hljs-string">'image'</span>));

            $data = array_merge($data, [
                <span class="hljs-string">'user_id'</span> => $request->user()->id,
                <span class="hljs-string">'image'</span> => asset(<span class="hljs-string">"storage/{$path}"</span>),
                <span class="hljs-string">'image_path'</span> => storage_path(<span class="hljs-string">'app/public'</span>) . <span class="hljs-string">"/{$path}"</span>,
            ]);

            $photo = Photo::create($data);

            <span class="hljs-keyword">return</span> response()->json([
                <span class="hljs-string">'status'</span> => <span class="hljs-string">'success'</span>,
                <span class="hljs-string">'data'</span> => $photo->load([<span class="hljs-string">'user'</span>, <span class="hljs-string">'comments'</span>])
            ]);
        }
    }
```

In the `PhotoController` above we have two methods. The `index` displays all the available photos, and the `store` saves a new photo to disk and database.

For the `photos` saved to be available to the public, we need to link the `storage` directory to the public directory. To do so run the command below:

```
    $ php artisan storage:link

```

![](//images.ctfassets.net/1es3ne0caaid/6jnvC8UIg0s4EOiU6wIEWg/3323c85e9a4f733865cd0efef1e44d0e/ios-push-notifications-social-network-storage-dir.png)

The command above will create a symlink from the `public/storage` directory to the `storage/app/public` directory that our photos will be uploaded to.

Open the `PhotoCommentController.php` in the `app/Http/Controllers` directory and replace the contents with the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Controllers</span>;

    <span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Photo</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">PhotoComment</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Request</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Notifications</span>\<span class="hljs-title">UserCommented</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PhotoCommentController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
    </span>{
        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span><span class="hljs-params">(Request $request)</span>
        </span>{
            $photo = Photo::with(<span class="hljs-string">'comments'</span>)->findOrFail($request->route(<span class="hljs-string">'photo'</span>));

            <span class="hljs-keyword">return</span> response()->json([<span class="hljs-string">'data'</span> => $photo->comments]);
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span><span class="hljs-params">(Request $request, Photo $photo)</span>
        </span>{
            $data = $request->validate([<span class="hljs-string">'comment'</span> => <span class="hljs-string">'required|string|between:2,500'</span>]);

            $comment = PhotoComment::create([
                <span class="hljs-string">'photo_id'</span> => $photo->id,
                <span class="hljs-string">'comment'</span> => $data[<span class="hljs-string">'comment'</span>],
                <span class="hljs-string">'user_id'</span> => $request->user()->id,
            ]);

            <span class="hljs-keyword">if</span> ($photo->user->allowsCommentsNotifications($request->user())) {
                $comment->notify(<span class="hljs-keyword">new</span> UserCommented($request->user(), $photo, $comment));
            }

            <span class="hljs-keyword">return</span> response()->json([
                <span class="hljs-string">'status'</span> => <span class="hljs-string">'success'</span>, 
                <span class="hljs-string">'data'</span> => $comment->load(<span class="hljs-string">'user'</span>)
            ]);
        }
    }
```

In the `PhotoCommentController` we have two methods. The `index` method displays all the comments for a single photo and the `store` creates a new comment.

In the `store` method on line 30, we have a call to a `notify` method and passes a nonexistent `UserCommented` class. This class is a [Laravel notification](https://laravel.com/docs/5.6/notifications) class. We will create this class later in the article. It’s needed to send notifications to the user when comments are made.

Create a `UserController` by running the command below:

```
    $ php artisan make:controller UserController

```

Next open the `UserController.php` in the `app/Http/Controllers` directory and replace the contents with the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Controllers</span>;

    <span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">User</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Facades</span>\<span class="hljs-title">Hash</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
    </span>{
        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span><span class="hljs-params">()</span>
        </span>{
            $users = [];

            User::with(<span class="hljs-string">'followers'</span>)->otherUsers()->get()->each(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">($user, $index)</span> <span class="hljs-title">use</span> <span class="hljs-params">(&$users)</span> </span>{
                $users[$index] = $user;
                $users[$index][<span class="hljs-string">'follows'</span>] = auth()->user()->isFollowing($user);
            });

            <span class="hljs-keyword">return</span> response()->json([<span class="hljs-string">'data'</span> => $users]);
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create</span><span class="hljs-params">(Request $request)</span>
        </span>{
            $credentials = $request->validate([
                <span class="hljs-string">'name'</span> => <span class="hljs-string">'required|string|max:255'</span>,
                <span class="hljs-string">'email'</span> => <span class="hljs-string">'required|string|email|max:255|unique:users'</span>,
                <span class="hljs-string">'password'</span> => <span class="hljs-string">'required|string|min:6'</span>,
            ]);

            $credentials[<span class="hljs-string">'password'</span>] = Hash::make($credentials[<span class="hljs-string">'password'</span>]);

            $user = User::create($credentials);

            $token = $user->createToken(config(<span class="hljs-string">'app.name'</span>));

            $data = [<span class="hljs-string">'user'</span> => $user, <span class="hljs-string">'access_token'</span> => $token->accessToken];

            <span class="hljs-keyword">return</span> response()->json([<span class="hljs-string">'data'</span> => $data, <span class="hljs-string">'status'</span> => <span class="hljs-string">'success'</span>]);
        }
    }
```

The `UserController` has two methods, one is the `index` method that returns all the users on the service, and the second is the `create` method that registers a new user and returns an access token that will be used for making authorized requests on behalf of the user.

Open the `UserFollowController.php` in the `app/Http/Controllers` directory and replace the contents with the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Controllers</span>;

    <span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">User</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">UserFollow</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Request</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserFollowController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
    </span>{
        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">follow</span><span class="hljs-params">(Request $request)</span>
        </span>{
            $user = User::findOrFail($request->get(<span class="hljs-string">'following_id'</span>));


            <span class="hljs-keyword">if</span> ($request->user()->isFollowing($user) == <span class="hljs-keyword">false</span>) {
                $request->user()->following()->save(
                    <span class="hljs-keyword">new</span> UserFollow($request->only(<span class="hljs-string">'following_id'</span>)
                ));
            }

            <span class="hljs-keyword">return</span> response()->json([<span class="hljs-string">'status'</span> => <span class="hljs-string">'success'</span>]);
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">unfollow</span><span class="hljs-params">(Request $request)</span>
        </span>{
            $user = User::findOrFail($request->get(<span class="hljs-string">'following_id'</span>));

            $request->user()->following()->whereFollowingId($user->id)->delete();

            <span class="hljs-keyword">return</span> response()->json([<span class="hljs-string">'status'</span> => <span class="hljs-string">'success'</span>]);
        }
    }
```

The controller above simply follows or unfollows a user.

Open the `UserSettingController.php` in the `app/Http/Controllers` directory and replace the contents with the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Controllers</span>;

    <span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">UserSetting</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Request</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserSettingController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
    </span>{
        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span><span class="hljs-params">()</span>
        </span>{
            <span class="hljs-keyword">return</span> response()->json(UserSetting::forCurrentUser()->first());
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update</span><span class="hljs-params">(Request $request)</span>
        </span>{
            $settings = $request->validate([
                <span class="hljs-string">'notification_comments'</span> => <span class="hljs-string">'in:Off,Following,Everyone'</span>,
            ]);

            $updated = $request->user()->settings()->update($settings);

            <span class="hljs-keyword">return</span> response()->json([<span class="hljs-string">'status'</span> => $updated ? <span class="hljs-string">'success'</span> : <span class="hljs-string">'error'</span>]);
        }
    }
```

In the controller above we return all the settings available for a user in the `index` method and then we update the settings for the user in the `update` method.

### Creating our application’s routes

Since we have created our controllers, let’s create our routes that link the URL to controllers. Open the `routes/api.php` file and replace the contents with the following:

```
    <span class="hljs-meta"><?php</span>

    Route::post(<span class="hljs-string">'/register'</span>, <span class="hljs-string">'UserController@create'</span>);

    Route::group([<span class="hljs-string">'middleware'</span> => <span class="hljs-string">'auth:api'</span>], <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> </span>{
        Route::get(<span class="hljs-string">'/users/settings'</span>, <span class="hljs-string">'UserSettingController@index'</span>);
        Route::put(<span class="hljs-string">'/users/settings'</span>, <span class="hljs-string">'UserSettingController@update'</span>);
        Route::post(<span class="hljs-string">'/users/follow'</span>, <span class="hljs-string">'UserFollowController@follow'</span>);
        Route::post(<span class="hljs-string">'/users/unfollow'</span>, <span class="hljs-string">'UserFollowController@unfollow'</span>);
        Route::get(<span class="hljs-string">'/users'</span>, <span class="hljs-string">'UserController@index'</span>);
        Route::get(<span class="hljs-string">'/photos/{photo}/comments'</span>, <span class="hljs-string">'PhotoCommentController@index'</span>);
        Route::post(<span class="hljs-string">'/photos/{photo}/comments'</span>, <span class="hljs-string">'PhotoCommentController@store'</span>);
        Route::resource(<span class="hljs-string">'/photos'</span>, <span class="hljs-string">'PhotoController'</span>)->only([<span class="hljs-string">'store'</span>, <span class="hljs-string">'index'</span>]);
    });
```

Above we have defined routes for our application. Each route points to a controller and a method in that controller that will handle the route. The route group above has a middleware applied, `auth:api`, this will make sure that every request to a route inside the group has to be authorized.

To manage authorization, let’s install Laravel passport.

### Installing Laravel Passport

Since we have many requests that require authorization, let’s install Laravel Passport. In the root directory of your project and run the following command:

```
    $ composer require laravel/passport

```

This will install Laravel Passport to the project. Open the `User` model in the `app` directory and `use` the `HasApiTokens` trait:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-comment">// [...]</span>

    <span class="hljs-keyword">use</span> <span class="hljs-title">Laravel</span>\<span class="hljs-title">Passport</span>\<span class="hljs-title">HasApiTokens</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Authenticatable</span>
    </span>{
        <span class="hljs-keyword">use</span> <span class="hljs-title">HasApiTokens</span>, <span class="hljs-title">Notifiable</span>;

        <span class="hljs-comment">// [...]</span>
    }
```

Next open the `AuthServiceProvider` class in the `app/Providers` directory and update it to the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-comment">// [...]</span>

    <span class="hljs-keyword">use</span> <span class="hljs-title">Laravel</span>\<span class="hljs-title">Passport</span>\<span class="hljs-title">Passport</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthServiceProvider</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ServiceProvider</span>
    </span>{
        <span class="hljs-comment">// [...]</span>

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">boot</span><span class="hljs-params">()</span>
        </span>{
            <span class="hljs-comment">// [...]</span>

            Passport::routes();
        }
    }
```

Open the `config/auth.php` configuration file and set the `driver` option of the `api` authentication guard to `passport`. This will instruct your application to use Passport's `TokenGuard` when authenticating incoming API requests:

```
    <span class="hljs-string">'guards'</span> => [
        <span class="hljs-comment">// [...]</span>

        <span class="hljs-string">'api'</span> => [
            <span class="hljs-string">'driver'</span> => <span class="hljs-string">'passport'</span>,
            <span class="hljs-string">'provider'</span> => <span class="hljs-string">'users'</span>,
        ],
    ],
```

To complete the installation, run the commands below, which will perform a migration and install Laravel Passport to your application:

```
    $ php artisan migrate
    $ php artisan passport:install

```

![](//images.ctfassets.net/1es3ne0caaid/3W31pKCdfW6Y8Eg4CYWqeO/6bca50e55ca38843ac3e82e0879797e0/ios-push-notifications-social-network-passport.png)

Passport is successfully installed after the commands finish execution. The `passport:install` command will create two files in the `storage` directory: `oauth-public.key` and `oauth-private.key`. These keys will be used to sign and validate access tokens.

> ⚠️ Copy and save the client ID and secret for the second client as you will need it later in the article.

### Adding push notification support

The next thing we want to do is add push notification support. For this, we will be using [Pusher Beams](https://pusher.com/beams). For convenience, we will be using a PHP library that is a Laravel supported wrapper for the [Pusher Beams PHP library](https://packagist.org/packages/pusher/pusher-push-notifications).

In your terminal run the following command:

```
    $ composer require neo/pusher-beams

```

When the installation is completed, open the `.env` file and add the following keys to the file:

```
    PUSHER_BEAMS_SECRET_KEY="PUSHER_BEAMS_SECRET_KEY"
    PUSHER_BEAMS_INSTANCE_ID="PUSHER_BEAMS_INSTANCE_ID"

```

> 💡 You need to replace the `PUSHER_BEAMS_SECRET_KEY` and `PUSHER_BEAMS_INSTANCE_ID` keys with the keys gotten from your Pusher dashboard.

Open the `broadcasting.php` file in the `config` directory and add the following keys to the pusher connection array:

```
    <span class="hljs-string">'connections'</span> => [
        <span class="hljs-string">'pusher'</span> => [
            <span class="hljs-comment">// [...]</span>

            <span class="hljs-string">'beams'</span> => [
                <span class="hljs-string">'secret_key'</span> => env(<span class="hljs-string">'PUSHER_BEAMS_SECRET_KEY'</span>),
                <span class="hljs-string">'instance_id'</span> => env(<span class="hljs-string">'PUSHER_BEAMS_INSTANCE_ID'</span>),
            ],

            <span class="hljs-comment">// [...]</span>
        ],
    ],
```

Next, create a new notification class where we will add our push notification. In your terminal run the command below to create the class:

```
    $ php artisan make:notification UserCommented

```

This will create a new `UserCommented` class in the `app/Notifications` directory. Open the file and replace the contents with the following:

```
    <span class="hljs-meta"><?php</span>

    <span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Notifications</span>;

    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Bus</span>\<span class="hljs-title">Queueable</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Notifications</span>\<span class="hljs-title">Notification</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">Neo</span>\<span class="hljs-title">PusherBeams</span>\<span class="hljs-title">PusherBeams</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">Neo</span>\<span class="hljs-title">PusherBeams</span>\<span class="hljs-title">PusherMessage</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">User</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">PhotoComment</span>;
    <span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Photo</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserCommented</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Notification</span>
    </span>{
        <span class="hljs-keyword">use</span> <span class="hljs-title">Queueable</span>;

        <span class="hljs-keyword">public</span> $user;

        <span class="hljs-keyword">public</span> $comment;

        <span class="hljs-keyword">public</span> $photo;

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span><span class="hljs-params">(User $user, Photo $photo, PhotoComment $comment)</span>
        </span>{
            <span class="hljs-keyword">$this</span>->user = $user;
            <span class="hljs-keyword">$this</span>->photo = $photo;
            <span class="hljs-keyword">$this</span>->comment = $comment;
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">via</span><span class="hljs-params">($notifiable)</span>
        </span>{
            <span class="hljs-keyword">return</span> [PusherBeams::class];
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toPushNotification</span><span class="hljs-params">($notifiable)</span>
        </span>{
            <span class="hljs-keyword">return</span> PusherMessage::create()
                ->iOS()
                ->sound(<span class="hljs-string">'success'</span>)
                ->title(<span class="hljs-string">'New Comment'</span>)
                ->body(<span class="hljs-string">"{$this->user->name} commented on your photo: {$this->comment->comment}"</span>)
                ->setOption(<span class="hljs-string">'apns.aps.mutable-content'</span>, <span class="hljs-number">1</span>)
                ->setOption(<span class="hljs-string">'apns.data.attachment-url'</span>, <span class="hljs-keyword">$this</span>->photo->image);
        }

        <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">pushNotificationInterest</span><span class="hljs-params">()</span>
        </span>{
            $id = <span class="hljs-keyword">$this</span>->photo->id;

            $audience = strtolower(<span class="hljs-keyword">$this</span>->user->settings->notification_comments);

            <span class="hljs-keyword">return</span> <span class="hljs-string">"photo_{$id}-comment_{$audience}"</span>;
        }
    }
```

In the class above we are extending a `Notification` class and we have implemented the `toPushNotification` method, which will be used to send the push notification when required. In the `via` method, we specify what channels we want to send the notification through and in the `pushNotificationInterest` we specify the interest we want to publish the push notification to.

If you remember earlier, we invoked the notification on line 30 of the `PhotoCommentController`.

> 💡 Read more about [Laravel Notifications](https://laravel.com/docs/5.6/notifications) and how it works.

That’s it. The backend application is complete. To start serving the application, run the following command:

```
    $ php artisan serve

```

This will start a PHP server running on port 8000.

## Building our iOS application using Swift

Now that we have a backend server that can serve us all the information we want and also send push notifications, let us create our iOS application, which will be the client application.

Launch Xcode and create a new ‘Single Page App’ project. Let's call it **Gram**. When the project is created, exit Xcode and `cd` to the root of the project using a terminal. In the root of the project create a `Podfile` and paste the following into the file:

```
    platform :ios, '11.0'

    target 'Gram' do
      use_frameworks!

      pod 'Alamofire', '~> 4.7.1'
      pod 'PushNotifications', '~> 0.10.6'
      pod 'NotificationBannerSwift'
    end

```

Then run the command below to start installing the dependencies we defined above:

```
    $ pod install

```

When the installation is complete, we will have a new `.xcworkspace` file in the root of the project. Double-click the workspace file to relaunch Xcode.

### Creating our storyboard

Next, let’s create our storyboard. Open your `Main.storyboard` file. We want to design it to look similar to this:

![](//images.ctfassets.net/1es3ne0caaid/3Q8zckYGGk8GaacuGWqS8a/dcb1a02957daf499b62218111bf2e12e/ios-push-notifications-social-network-main-storyboard.png)

### How the storyboard scenes are connected

The first scene we have a launch view controller. This controller connects to the login scene, register scene or the main navigation controller depending on the login status of the user. The login and register scenes are basic and they simply authenticate the user.

The main navigation controller connects to the main controller that displays the timeline. From that scene, there are connections to the settings scene, the search scene, and the view comments scene. Each segue connection is given an identifier so we can present them from the controller code.

When you are done creating the storyboard, let’s create the custom classes for each storyboard scene.

### Creating our models

To help us with managing our API’s JSON responses we will be using [Codable in Swift 4](https://paper.dropbox.com/doc/Swift-4-decoding-JSON-using-Codable-o9T8RFPWqR3nhodGEt0d1). This will make it extremely easy for us to manage the responses from the API.

Create a new file named `Models.swift` and paste this in the file:

```
    <span class="hljs-keyword">import</span> Foundation

    <span class="hljs-keyword">typealias</span> <span class="hljs-type">Users</span> = [<span class="hljs-type">User</span>]
    <span class="hljs-keyword">typealias</span> <span class="hljs-type">Photos</span> = [<span class="hljs-type">Photo</span>]
    <span class="hljs-keyword">typealias</span> <span class="hljs-type">PhotoComments</span> = [<span class="hljs-type">PhotoComment</span>]

    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">User</span>: <span class="hljs-title">Codable</span> </span>{
        <span class="hljs-keyword">var</span> id: <span class="hljs-type">Int</span>
        <span class="hljs-keyword">var</span> name: <span class="hljs-type">String</span>
        <span class="hljs-keyword">var</span> email: <span class="hljs-type">String</span>
        <span class="hljs-keyword">var</span> follows: <span class="hljs-type">Bool</span>?
    }

    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Photo</span>: <span class="hljs-title">Codable</span> </span>{
        <span class="hljs-keyword">var</span> id: <span class="hljs-type">Int</span>
        <span class="hljs-keyword">var</span> user: <span class="hljs-type">User</span>
        <span class="hljs-keyword">var</span> image: <span class="hljs-type">String</span>
        <span class="hljs-keyword">var</span> caption: <span class="hljs-type">String</span>
        <span class="hljs-keyword">var</span> comments: <span class="hljs-type">PhotoComments</span>    
    }

    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">PhotoComment</span>: <span class="hljs-title">Codable</span> </span>{
        <span class="hljs-keyword">var</span> id: <span class="hljs-type">Int</span>
        <span class="hljs-keyword">var</span> user: <span class="hljs-type">User</span>
        <span class="hljs-keyword">var</span> photo_id: <span class="hljs-type">Int</span>
        <span class="hljs-keyword">var</span> user_id: <span class="hljs-type">Int</span>
        <span class="hljs-keyword">var</span> comment: <span class="hljs-type">String</span>
    }
```

### Creating our services

Our services will contain code that we will need to make calls to the API and also other functionality that interacts with the application view.

Create a new class `SettingsService` and paste the following code into the file:

```
    <span class="hljs-keyword">import</span> Foundation

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SettingsService</span>: <span class="hljs-title">NSObject</span> </span>{

        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> shared = <span class="hljs-type">SettingsService</span>()    
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> key = <span class="hljs-string">"gram.settings.notifications"</span>
        <span class="hljs-keyword">var</span> settings: [<span class="hljs-type">String</span>: <span class="hljs-type">String</span>] = [:];

        <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> allSettings: [<span class="hljs-type">String</span>: <span class="hljs-type">String</span>] {
            <span class="hljs-keyword">set</span> {
                <span class="hljs-keyword">self</span>.settings = newValue
            }
            <span class="hljs-keyword">get</span> {
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> settings = loadFromDefaults(), settings[<span class="hljs-string">"notification_comments"</span>] != <span class="hljs-literal">nil</span> {
                    <span class="hljs-keyword">return</span> settings
                }

                <span class="hljs-keyword">return</span> [
                    <span class="hljs-string">"notification_comments"</span>: <span class="hljs-type">Setting</span>.<span class="hljs-type">Notification</span>.<span class="hljs-type">Comments</span>.following.<span class="hljs-built_in">toString</span>()
                ];
            }
        }

        <span class="hljs-keyword">override</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">init</span>() {
            <span class="hljs-keyword">super</span>.<span class="hljs-keyword">init</span>()
            <span class="hljs-keyword">self</span>.settings = <span class="hljs-keyword">self</span>.allSettings
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">loadFromDefaults</span><span class="hljs-params">()</span></span> -> [<span class="hljs-type">String</span>: <span class="hljs-type">String</span>]? {
            <span class="hljs-keyword">return</span> <span class="hljs-type">UserDefaults</span>.standard.dictionary(forKey: <span class="hljs-type">SettingsService</span>.key) <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>: <span class="hljs-type">String</span>]
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">loadFromApi</span><span class="hljs-params">()</span></span> {
            <span class="hljs-type">ApiService</span>.shared.loadSettings { settings <span class="hljs-keyword">in</span>
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> settings = settings {
                    <span class="hljs-keyword">self</span>.allSettings = settings
                    <span class="hljs-keyword">self</span>.saveSettings(saveRemotely: <span class="hljs-literal">false</span>)
                }
            }
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateCommentsNotificationSetting</span><span class="hljs-params">(<span class="hljs-number">_</span> status: Setting.Notification.Comments)</span></span> {
            <span class="hljs-keyword">self</span>.allSettings[<span class="hljs-string">"notification_comments"</span>] = status.<span class="hljs-built_in">toString</span>()
            saveSettings()
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">saveSettings</span><span class="hljs-params">(saveRemotely: Bool = <span class="hljs-literal">true</span>)</span></span> {
            <span class="hljs-type">UserDefaults</span>.standard.<span class="hljs-keyword">set</span>(settings, forKey: <span class="hljs-type">SettingsService</span>.key)

            <span class="hljs-keyword">if</span> saveRemotely == <span class="hljs-literal">true</span> {
                <span class="hljs-type">ApiService</span>.shared.saveSettings(settings: settings) { <span class="hljs-number">_</span> <span class="hljs-keyword">in</span> }
            }
        }
    }
```

In the class above we have defined the settings service. The class is how we manage settings for our application. In the `allSettings` setter, we attempt to fetch the settings from the local store and if we cant, we return some sensible defaults.

We have the `loadFromDefaults` method that loads the settings locally from the `UserDefaults`, the `loadFromApi` class that loads settings from the API using the `ApiService`, the `updateCommentsNotificationSetting`, which updates the comment notification settings. Finally, we have the `saveSettings` method that saves the comment locally and remotely.

In the same file, add the following `enum` to the bottom:

```
    <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Setting</span> </span>{ 
        <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Notification</span> </span>{            
            <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Comments</span>: <span class="hljs-title">String</span> </span>{
                <span class="hljs-keyword">case</span> off = <span class="hljs-string">"Off"</span>
                <span class="hljs-keyword">case</span> everyone = <span class="hljs-string">"Everyone"</span>
                <span class="hljs-keyword">case</span> following = <span class="hljs-string">"Following"</span>

                <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">toString</span><span class="hljs-params">()</span></span> -> <span class="hljs-type">String</span> {
                    <span class="hljs-keyword">return</span> <span class="hljs-keyword">self</span>.rawValue
                }
            }
        }    
    }
```

The enum is basically a representation of the available settings for our comment notifications.

The next service we want to define is the `AuthService`. This service is used to authenticate users of our service. Create a new `AuthService` class and paste the following code into it:

```
    <span class="hljs-keyword">import</span> Foundation

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthService</span>: <span class="hljs-title">NSObject</span> </span>{
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> key = <span class="hljs-string">"gram-token"</span>
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> shared = <span class="hljs-type">AuthService</span>()

        <span class="hljs-keyword">typealias</span> <span class="hljs-type">AccessToken</span> = <span class="hljs-type">String</span>    
        <span class="hljs-keyword">typealias</span> <span class="hljs-type">LoginCredentials</span> = (email: <span class="hljs-type">String</span>, password: <span class="hljs-type">String</span>)
        <span class="hljs-keyword">typealias</span> <span class="hljs-type">SignupCredentials</span> = (name: <span class="hljs-type">String</span>, email: <span class="hljs-type">String</span>, password: <span class="hljs-type">String</span>)

        <span class="hljs-keyword">override</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">init</span>() {
            <span class="hljs-keyword">super</span>.<span class="hljs-keyword">init</span>()
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">loggedIn</span><span class="hljs-params">()</span></span> -> <span class="hljs-type">Bool</span> {
            <span class="hljs-keyword">return</span> getToken() != <span class="hljs-literal">nil</span>
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">logout</span><span class="hljs-params">()</span></span> {
            <span class="hljs-type">UserDefaults</span>.standard.removeObject(forKey: <span class="hljs-type">AuthService</span>.key)
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getToken</span><span class="hljs-params">()</span></span> -> <span class="hljs-type">AccessToken</span>? {
            <span class="hljs-keyword">return</span> <span class="hljs-type">UserDefaults</span>.standard.string(forKey: <span class="hljs-type">AuthService</span>.key)
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">saveToken</span><span class="hljs-params">(<span class="hljs-number">_</span> token: AccessToken)</span></span> -> <span class="hljs-type">AuthService</span> {
            <span class="hljs-type">UserDefaults</span>.standard.<span class="hljs-keyword">set</span>(token, forKey: <span class="hljs-type">AuthService</span>.key)
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">self</span>
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">deleteToken</span><span class="hljs-params">()</span></span> -> <span class="hljs-type">AuthService</span> {
            <span class="hljs-type">UserDefaults</span>.standard.removeObject(forKey: <span class="hljs-type">AuthService</span>.key)
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">self</span>
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">then</span><span class="hljs-params">(completion: @escaping<span class="hljs-params">()</span></span></span> -> <span class="hljs-type">Void</span>) {
            completion()
        }
    }
```

The class above is fairly straightforward and it provides methods for authentication. It has the `getToken` and `saveToken`, which essentially retrieves and saves the access token gotten after authenticating the user.

Next, let’s create our final service, the `ApiService`. Create a new class `ApiService` and paste the following into the file:

```
    <span class="hljs-keyword">import</span> Foundation
    <span class="hljs-keyword">import</span> Alamofire

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ApiService</span>: <span class="hljs-title">NSObject</span> </span>{

        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> shared = <span class="hljs-type">ApiService</span>()

        <span class="hljs-keyword">override</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">init</span>() {
            <span class="hljs-keyword">super</span>.<span class="hljs-keyword">init</span>()
        }
    }
```

Now that we have the base of the class, let’s start adding methods to the class. Since it is a large class, we will split adding the methods over a few paragraphs.

In the class, let’s add our first set of methods, which will handle authentication:

```
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">login</span><span class="hljs-params">(credentials: AuthService.LoginCredentials, completion: @escaping<span class="hljs-params">(AuthService.AccessToken?, ApiError?)</span></span></span> -> <span class="hljs-type">Void</span>) {
        <span class="hljs-keyword">let</span> params = [
            <span class="hljs-string">"username"</span>: credentials.email,
            <span class="hljs-string">"password"</span>: credentials.password,
            <span class="hljs-string">"grant_type"</span>: <span class="hljs-string">"password"</span>,
            <span class="hljs-string">"client_id"</span>: <span class="hljs-type">AppConstants</span>.<span class="hljs-type">API_CLIENT_ID</span>,
            <span class="hljs-string">"client_secret"</span>: <span class="hljs-type">AppConstants</span>.<span class="hljs-type">API_CLIENT_SECRET</span>
        ]

        request(.post, url: <span class="hljs-string">"/oauth/token"</span>, params: params, auth: <span class="hljs-literal">false</span>) { data <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> data = data <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> completion(<span class="hljs-literal">nil</span>, .badCredentials) }
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> token = data[<span class="hljs-string">"access_token"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> completion(<span class="hljs-literal">nil</span>, .badResponse) }

            completion(token, <span class="hljs-literal">nil</span>)
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">signup</span><span class="hljs-params">(credentials: AuthService.SignupCredentials, completion: @escaping<span class="hljs-params">(AuthService.AccessToken?, ApiError?)</span></span></span> -> <span class="hljs-type">Void</span>) {
        <span class="hljs-keyword">let</span> params = [
            <span class="hljs-string">"name"</span>: credentials.name,
            <span class="hljs-string">"email"</span>: credentials.email,
            <span class="hljs-string">"password"</span>: credentials.password
        ]

        request(.post, url: <span class="hljs-string">"/api/register"</span>, params: params, auth: <span class="hljs-literal">false</span>) { data <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> res = data, <span class="hljs-keyword">let</span> data = res[<span class="hljs-string">"data"</span>] <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>:<span class="hljs-type">AnyObject</span>] <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> completion(<span class="hljs-literal">nil</span>, .badCredentials)
            }

            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> token = data[<span class="hljs-string">"access_token"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> completion(<span class="hljs-literal">nil</span>, .badResponse)
            }

            completion(token, <span class="hljs-literal">nil</span>)
        }
    }
```

Next let’s add the methods for loading users, loading posts, loading comments and adding comments to the `ApiService` class:

```
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fetchUsers</span><span class="hljs-params">(completion: @escaping<span class="hljs-params">(Users?)</span></span></span> -> <span class="hljs-type">Void</span>) {
        request(.<span class="hljs-keyword">get</span>, url: <span class="hljs-string">"/api/users"</span>) { data <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">self</span>.responseToJsonStringData(response: data) {
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> obj = <span class="hljs-keyword">try</span>? <span class="hljs-type">JSONDecoder</span>().decode(<span class="hljs-type">Users</span>.<span class="hljs-keyword">self</span>, from: data) {
                    <span class="hljs-keyword">return</span> completion(obj)
                }
            }

            completion(<span class="hljs-literal">nil</span>)
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fetchPosts</span><span class="hljs-params">(completion: @escaping<span class="hljs-params">(Photos?)</span></span></span> -> <span class="hljs-type">Void</span>) {
        request(.<span class="hljs-keyword">get</span>, url: <span class="hljs-string">"/api/photos"</span>) { data <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">self</span>.responseToJsonStringData(response: data) {
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> obj = <span class="hljs-keyword">try</span>? <span class="hljs-type">JSONDecoder</span>().decode(<span class="hljs-type">Photos</span>.<span class="hljs-keyword">self</span>, from: data) {
                    <span class="hljs-keyword">return</span> completion(obj)
                }
            }

            completion(<span class="hljs-literal">nil</span>)
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fetchComments</span><span class="hljs-params">(forPhoto id: Int, completion: @escaping<span class="hljs-params">(PhotoComments?)</span></span></span> -> <span class="hljs-type">Void</span>) {
        request(.<span class="hljs-keyword">get</span>, url: <span class="hljs-string">"/api/photos/\(id)/comments"</span>) { data <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">self</span>.responseToJsonStringData(response: data) {
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> obj = <span class="hljs-keyword">try</span>? <span class="hljs-type">JSONDecoder</span>().decode(<span class="hljs-type">PhotoComments</span>.<span class="hljs-keyword">self</span>, from: data) {
                    <span class="hljs-keyword">return</span> completion(obj)
                }
            }

            completion(<span class="hljs-literal">nil</span>)
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">leaveComment</span><span class="hljs-params">(forId id: Int, comment: String, completion: @escaping<span class="hljs-params">(PhotoComment?)</span></span></span> -> <span class="hljs-type">Void</span>) {
        request(.post, url: <span class="hljs-string">"/api/photos/\(id)/comments"</span>, params: [<span class="hljs-string">"comment"</span>: comment]) { data <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> res = data, <span class="hljs-keyword">let</span> data = res[<span class="hljs-string">"data"</span>] <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>: <span class="hljs-type">AnyObject</span>],
                <span class="hljs-keyword">let</span> json = <span class="hljs-keyword">try</span>? <span class="hljs-type">JSONSerialization</span>.data(withJSONObject: data, options: []),
                <span class="hljs-keyword">let</span> jsonString = <span class="hljs-type">String</span>(data: json, encoding: .utf8),
                <span class="hljs-keyword">let</span> jsonData = jsonString.data(using: .utf8),
                <span class="hljs-keyword">let</span> obj = <span class="hljs-keyword">try</span>? <span class="hljs-type">JSONDecoder</span>().decode(<span class="hljs-type">PhotoComment</span>.<span class="hljs-keyword">self</span>, from: jsonData) {
                    <span class="hljs-keyword">return</span> completion(obj)
            }

            completion(<span class="hljs-literal">nil</span>)
        }
    }
```

In the methods above, you’ll notice we decode the JSON response from the API into the appropriate model object. This makes it easier to work with in our controllers.

The next methods we will add will be to follow or unfollow a user, load settings for a user and update settings for a user. Add the methods below to the `ApiService`:

```
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">toggleFollowStatus</span><span class="hljs-params">(forUserId id: Int, following: Bool, completion: @escaping<span class="hljs-params">(Bool?)</span></span></span> -> <span class="hljs-type">Void</span>) {
        <span class="hljs-keyword">let</span> status = following ? <span class="hljs-string">"unfollow"</span> : <span class="hljs-string">"follow"</span>

        request(.post, url: <span class="hljs-string">"/api/users/\((status))"</span>, params: [<span class="hljs-string">"following_id"</span>: id]) { data <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> res = data <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>: <span class="hljs-type">String</span>], res[<span class="hljs-string">"status"</span>] == <span class="hljs-string">"success"</span> <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> completion(<span class="hljs-literal">false</span>)
            }

            completion(<span class="hljs-literal">true</span>)
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">loadSettings</span><span class="hljs-params">(completion: @escaping<span class="hljs-params">([String: String]?)</span></span></span> -> <span class="hljs-type">Void</span>) {
        request(.<span class="hljs-keyword">get</span>, url: <span class="hljs-string">"/api/users/settings"</span>) { data <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> settings = data <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>: <span class="hljs-type">String</span>] <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> completion(<span class="hljs-literal">nil</span>)
            }

            completion(settings)
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">saveSettings</span><span class="hljs-params">(settings: [String: String], completion: @escaping<span class="hljs-params">(Bool)</span></span></span> -> <span class="hljs-type">Void</span>) {
        request(.put, url: <span class="hljs-string">"/api/users/settings"</span>, params: settings) { data <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> res = data <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>: <span class="hljs-type">String</span>], res[<span class="hljs-string">"status"</span>] == <span class="hljs-string">"success"</span> <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> completion(<span class="hljs-literal">false</span>)
            }

            completion(<span class="hljs-literal">true</span>)
        }
    }
```

The next method we want to add is the `uploadImage` method. This method is responsible for taking the selected image and caption and sending it to the API for uploading. Add the method below to the `ApiService` class:

```
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">uploadImage</span><span class="hljs-params">(<span class="hljs-number">_</span> image: Data, caption: String, name: String, completion: @escaping<span class="hljs-params">(Photo?, ApiError?)</span></span></span> -> <span class="hljs-type">Void</span>) {
        <span class="hljs-keyword">let</span> url = <span class="hljs-keyword">self</span>.url(appending: <span class="hljs-string">"/api/photos"</span>)

        <span class="hljs-comment">// Handles multipart data</span>
        <span class="hljs-keyword">let</span> multipartHandler: (<span class="hljs-type">MultipartFormData</span>) -> <span class="hljs-type">Void</span> = { multipartFormData <span class="hljs-keyword">in</span>
            multipartFormData.append(caption.data(using: .utf8)!, withName: <span class="hljs-string">"caption"</span>)
            multipartFormData.append(image, withName: <span class="hljs-string">"image"</span>, fileName: name, mimeType: <span class="hljs-string">"image/jpeg"</span>)
        }

        <span class="hljs-type">Alamofire</span>.upload(
            multipartFormData: multipartHandler,
            usingThreshold: <span class="hljs-type">UInt64</span>.<span class="hljs-keyword">init</span>(),
            to: url,
            method: .post,
            headers: requestHeaders(),
            encodingCompletion: { encodingResult <span class="hljs-keyword">in</span>
                <span class="hljs-keyword">let</span> uploadedHandler: (<span class="hljs-type">DataResponse</span><<span class="hljs-type">Any</span>>) -> <span class="hljs-type">Void</span> = { response <span class="hljs-keyword">in</span>
                    <span class="hljs-keyword">if</span> response.result.isSuccess,
                        <span class="hljs-keyword">let</span> resp = response.result.value <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>: <span class="hljs-type">AnyObject</span>],
                        <span class="hljs-keyword">let</span> data = resp[<span class="hljs-string">"data"</span>] <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>: <span class="hljs-type">AnyObject</span>],
                        <span class="hljs-keyword">let</span> json = <span class="hljs-keyword">try</span>? <span class="hljs-type">JSONSerialization</span>.data(withJSONObject: data, options: []),
                        <span class="hljs-keyword">let</span> jsonString = <span class="hljs-type">String</span>(data: json, encoding: .utf8),
                        <span class="hljs-keyword">let</span> jsonData = jsonString.data(using: .utf8),
                        <span class="hljs-keyword">let</span> obj = <span class="hljs-keyword">try</span>? <span class="hljs-type">JSONDecoder</span>().decode(<span class="hljs-type">Photo</span>.<span class="hljs-keyword">self</span>, from: jsonData) {
                            <span class="hljs-keyword">return</span> completion(obj, <span class="hljs-literal">nil</span>)
                    }

                    completion(<span class="hljs-literal">nil</span>, .uploadError(<span class="hljs-literal">nil</span>))
                }

                <span class="hljs-keyword">switch</span> encodingResult {
                <span class="hljs-keyword">case</span> .failure(<span class="hljs-number">_</span>): completion(<span class="hljs-literal">nil</span>, .uploadError(<span class="hljs-literal">nil</span>))
                <span class="hljs-keyword">case</span> .success(<span class="hljs-keyword">let</span> upload, <span class="hljs-number">_</span>, <span class="hljs-number">_</span>): upload.responseJSON(completionHandler: uploadedHandler)
                }
            }
        )
    }
```

Next let’s add the class’ helper methods.

```
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">url</span><span class="hljs-params">(appending: URLConvertible)</span></span> -> <span class="hljs-type">URLConvertible</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-string">"\(AppConstants.API_URL)\(appending)"</span>
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">requestHeaders</span><span class="hljs-params">(auth: Bool = <span class="hljs-literal">true</span>)</span></span> -> <span class="hljs-type">HTTPHeaders</span> {
        <span class="hljs-keyword">var</span> headers: <span class="hljs-type">HTTPHeaders</span> = [<span class="hljs-string">"Accept"</span>: <span class="hljs-string">"application/json"</span>]

        <span class="hljs-keyword">if</span> auth && <span class="hljs-type">AuthService</span>.shared.loggedIn() {
            headers[<span class="hljs-string">"Authorization"</span>] = <span class="hljs-string">"Bearer \(AuthService.shared.getToken()!)"</span>
        }

        <span class="hljs-keyword">return</span> headers
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">request</span><span class="hljs-params">(<span class="hljs-number">_</span> method: HTTPMethod, url: URLConvertible, params: Parameters? = <span class="hljs-literal">nil</span>, auth: Bool = <span class="hljs-literal">true</span>, handler: @escaping <span class="hljs-params">([String: AnyObject]?)</span></span></span> -> <span class="hljs-type">Void</span>) {
        <span class="hljs-keyword">let</span> url = <span class="hljs-keyword">self</span>.url(appending: url)

        <span class="hljs-type">Alamofire</span>
            .request(url, method: method, parameters: params, encoding: <span class="hljs-type">JSONEncoding</span>.<span class="hljs-keyword">default</span>, headers: requestHeaders(auth: auth))
            .validate()
            .responseJSON { resp <span class="hljs-keyword">in</span>
                <span class="hljs-keyword">guard</span> resp.result.isSuccess, <span class="hljs-keyword">let</span> data = resp.result.value <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>: <span class="hljs-type">AnyObject</span>] <span class="hljs-keyword">else</span> {
                    <span class="hljs-keyword">return</span> handler(<span class="hljs-literal">nil</span>)
                }

                handler(data)
            }
    } 

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">responseToJsonStringData</span><span class="hljs-params">(response data: [String: AnyObject]?)</span></span> -> <span class="hljs-type">Data</span>? {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> res = data, <span class="hljs-keyword">let</span> data = res[<span class="hljs-string">"data"</span>] <span class="hljs-keyword">as</span>? [[<span class="hljs-type">String</span>: <span class="hljs-type">AnyObject</span>]] {
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> json = <span class="hljs-keyword">try</span>? <span class="hljs-type">JSONSerialization</span>.data(withJSONObject: data, options: []) {
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> jsonString = <span class="hljs-type">String</span>(data: json, encoding: .utf8), <span class="hljs-keyword">let</span> data = jsonString.data(using: .utf8) {
                    <span class="hljs-keyword">return</span> data
                }
            }
        }

        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
    }
```

The `url` method takes a URL path and appends the base API URL to it. The `requestHeaders` method attaches the appropriate headers to the request sent by Alamofire. The `request` method is a wrapper around Alamofire that sends requests to the API for us. The `responseToJsonStringData` converts the data from our JSON file into a JSON string which can then be decoded into one of our `Codable` models.

One final thing we want to add to the bottom of the `ApiService` class is the `enum` for `ApiError`s. In the same file at the bottom, add the following code:

```
    <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">ApiError</span>: <span class="hljs-title">Error</span> </span>{
        <span class="hljs-keyword">case</span> badResponse
        <span class="hljs-keyword">case</span> badCredentials
        <span class="hljs-keyword">case</span> uploadError([<span class="hljs-type">String</span>: [<span class="hljs-type">String</span>]]?)
    }
```

That’s all for the `ApiService` and indeed all the applications services. In the next part we will continue building our iOS application.

## Conclusion

In this first part of the article, we have seen how we can create an API for our social network application using Laravel. We also integrated push notifications on the server side using Pusher Beams.

In the [next part](https://dev.to/neo/send-push-notifications-in-a-social-network-ios-app---part-2-build-the-app-3d8p), we will build the client IOS application using Swift. We will also integrate push notifications to our social network application using Pusher Beams.

The source code to the application is on [GitHub](https://github.com/neoighodaro-articles/pusher-beams-ios-social-network).

This post first appeared on the [Pusher blog](https://pusher.com/tutorials/social-notifications-ios-part-1).