With the rise of mobile development and JavaScript frameworks, using a RESTful API is the best option to build a single interface between your data and your client.

Laravel is a PHP framework developed with PHP developer productivity in mind. Written and maintained by Taylor Otwell, the framework is very opinionated and strives to save developer time by favoring convention over configuration. The framework also aims to evolve with the web and has already incorporated several new features and ideas in the web development world—such as job queues, API authentication out of the box, real-time communication, and much more.

Laravel API Tutorial - Building a RESTful Web service

In this tutorial, we’ll explore the ways you can build—and test—a robust API using Laravel with authentication. We’ll be using Laravel 5.4, and all of the code is available for reference on GitHub.

RESTful APIs

First, we need to understand what exactly is considered a RESTful API. REST stands for REpresentational State Transfer and is an architectural style for network communication between applications, which relies on a stateless protocol (usually HTTP) for interaction.

HTTP Verbs Represent Actions

In RESTful APIs, we use the HTTP verbs as actions, and the endpoints are the resources acted upon. We’ll be using the HTTP verbs for their semantic meaning:

  • GET: retrieve resources
  • POST: create resources
  • PUT: update resources
  • DELETE: delete resources
HTTP verbs: GET, POST, PUT and DELETE are actions in RESTful APIs

Update Action: PUT vs. POST

RESTful APIs are a matter of much debate and there are plenty of opinions out there on whether is best to update with POSTPATCH, or PUT, or if the create action is best left to the PUT verb. In this article we’ll be using PUT for the update action, as according to the HTTP RFC, PUT means to create/update a resource at a specific location. Another requirement for the PUT verb is idempotence, which in this case basically means you can send that request 1, 2 or 1000 times and the result will be the same: one updated resource in the database.

Resources

Resources will be the targets of the actions, in our case Articles and Users, and they have their own endpoints:

  • /articles
  • /users

In this laravel api tutorial, the resources will have a 1:1 representation on our data models, but that is not a requirement. You can have resources represented in more than one data model (or not represented at all in the database) and models completely off limits for the user. In the end, you get to decide how to architect resources and models in a way that is fitting to your application.

A Note on Consistency

The greatest advantage of using a set of conventions such as REST is that your API will be much easier to consume and develop around. Some endpoints are pretty straightforward and, as a result, your API will be much more easier to use and maintain as opposed to having endpoints such as GET /get_article?id_article=12 and POST /delete_article?number=40. I’ve built terrible APIs like that in the past and I still hate myself for it.

However, there will be cases where it will be hard to map to a Create/Retrieve/Update/Delete schema. Remember that the URLs should not contain verbs and that resources are not necessarily rows in a table. Another thing to keep in mind is that you don’t have to implement every action for every resource.

Setting Up a Laravel Web Service Project

As with all modern PHP frameworks, we’ll need Composer to install and handle our dependencies. After you follow the download instructions (and add to your path environment variable), install Laravel using the command:

$ composer global require laravel/installer

After the installation finishes, you can scaffold a new application like this:

$ laravel new myapp

For the above command, you need to have ~/composer/vendor/bin in your $PATH. If you don’t want to deal with that, you can also create a new project using Composer:

$ composer create-project --prefer-dist laravel/laravel myapp

With Laravel installed, you should be able to start the server and test if everything is working:

$ php artisan serve
Laravel development server started: <http://127.0.0.1:8000>
When you open localhost:8000 on your browser, you should see the Laravel sample page
When you open localhost:8000 on your browser, you should see this sample page.

Migrations and Models

Before actually writing your first migration, make sure you have a database created for this app and add its credentials to the .env file located in the root of the project.

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

You can also use Homestead, a Vagrant box specially crafted for Laravel, but that is a bit out of the scope of this article. If you’d like to know more, refer to the Homestead documentation.

Let’s get started with our first model and migration—the Article. The article should have a title and a body field, as well as a creation date. Laravel provides several commands through Artisan—Laravel’s command line tool—that help us by generating files and putting them in the correct folders. To create the Article model, we can run:

$ php artisan make:model Article -m

The -m option is short for --migration and it tells Artisan to create one for our model. Here’s the generated migration:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateArticlesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('articles');
    }
}

Let’s dissect this for a second:

  • The up() and down() methods will be run when we migrate and rollback respectively;
  • $table->increments('id') sets up an auto incrementing integer with the name id;
  • $table->timestamps() will set up the timestamps for us—created_at and updated_at, but don’t worry about setting a default, Laravel takes care of updating these fields when needed.
  • And finally, Schema::dropIfExists() will, of course, drop the table if it exists.

With that out of the way, let’s add two lines to our up() method:

public function up()
{
    Schema::create('articles', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->text('body');
        $table->timestamps();
    });
}

The string() method creates a VARCHAR equivalent column while text() creates a TEXTequivalent. With that done, let’s go ahead and migrate:

$ php artisan migrate

You can also use the --step option here, and it will separate each migration into its own batch so that you can roll them back individually if needed.

Laravel out of the box comes with two migrations, create_users_table and create_password_resets_table. We won’t be using the password_resets table, but having the users table ready for us will be helpful.

Now let’s go back to our model and add those attributes to the $fillable field so that we can use them in our Article::create and Article::update models:

class Article extends Model
{
    protected $fillable = ['title', 'body'];
}

Fields inside the $fillable property can be mass assigned using Eloquent’s create() and update()methods. You can also use the $guarded property, to allow all but a few properties.

Database Seeding

Database seeding is the process of filling up our database with dummy data that we can use to test it. Laravel comes with Faker, a great library for generating just the correct format of dummy data for us. So let’s create our first seeder:

$ php artisan make:seeder ArticlesTableSeeder

The seeders will be located in the /database/seeds directory. Here’s how it looks like after we set it up to create a few articles:

class ArticlesTableSeeder extends Seeder
{
    public function run()
    {
        // Let's truncate our existing records to start from scratch.
        Article::truncate();

        $faker = \Faker\Factory::create();

        // And now, let's create a few articles in our database:
        for ($i = 0; $i < 50; $i++) {
            Article::create([
                'title' => $faker->sentence,
                'body' => $faker->paragraph,
            ]);
        }
    }
}

So let’s run the seed command:

$ php artisan db:seed --class=ArticlesTableSeeder

Let’s repeat the process to create a Users seeder:

class UsersTableSeeder extends Seeder
{
    public function run()
    {
        // Let's clear the users table first
        User::truncate();

        $faker = \Faker\Factory::create();

        // Let's make sure everyone has the same password and 
        // let's hash it before the loop, or else our seeder 
        // will be too slow.
        $password = Hash::make('toptal');

        User::create([
            'name' => 'Administrator',
            'email' => 'admin@test.com',
            'password' => $password,
        ]);

        // And now let's generate a few dozen users for our app:
        for ($i = 0; $i < 10; $i++) {
            User::create([
                'name' => $faker->name,
                'email' => $faker->email,
                'password' => $password,
            ]);
        }
    }
}

We can make it easier by adding our seeders to the main DatabaseSeeder class inside the database/seedsfolder:

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $this->call(ArticlesTableSeeder::class);
        $this->call(UsersTableSeeder::class);
    }
}

This way, we can simply run $ php artisan db:seed and it will run all the called classes in the run() method.

Routes and Controllers

Let’s create the basic endpoints for our application: create, retrieve the list, retrieve a single one, update, and delete. On the routes/api.php file, we can simply do this:

Use App\Article;
 
Route::get('articles', function() {
    // If the Content-Type and Accept headers are set to 'application/json', 
    // this will return a JSON structure. This will be cleaned up later.
    return Article::all();
});
 
Route::get('articles/{id}', function($id) {
    return Article::find($id);
});

Route::post('articles', function(Request $request) {
    return Article::create($request->all);
});

Route::put('articles/{id}', function(Request $request, $id) {
    $article = Article::findOrFail($id);
    $article->update($request->all());

    return $article;
});

Route::delete('articles/{id}', function($id) {
    Article::find($id)->delete();

    return 204;
})

The routes inside api.php will be prefixed with /api/ and the API throttling middleware will be automatically applied to these routes (if you want to remove the prefix you can edit the RouteServiceProvider class on /app/Providers/RouteServiceProvider.php).

Now let’s move this code to its own Controller:

$ php artisan make:controller ArticleController

ArticleController.php:

use App\Article;
 
class ArticleController extends Controller
{
    public function index()
    {
        return Article::all();
    }
 
    public function show($id)
    {
        return Article::find($id);
    }

    public function store(Request $request)
    {
        return Article::create($request->all());
    }

    public function update(Request $request, $id)
    {
        $article = Article::findOrFail($id);
        $article->update($request->all());

        return $article;
    }

    public function delete(Request $request, $id)
    {
        $article = Article::findOrFail($id);
        $article->delete();

        return 204;
    }
}

The routes/api.php file:

Route::get('articles', 'ArticleController@index');
Route::get('articles/{id}', 'ArticleController@show');
Route::post('articles', 'ArticleController@store');
Route::put('articles/{id}', 'ArticleController@update');
Route::delete('articles/{id}', 'ArticleController@delete');

We can improve the endpoints by using implicit route model binding. This way, Laravel will inject the Articleinstance in our methods and automatically return a 404 if it isn’t found. We’ll have to make changes on the routes file and on the controller:

Route::get('articles', 'ArticleController@index');
Route::get('articles/{article}', 'ArticleController@show');
Route::post('articles', 'ArticleController@store');
Route::put('articles/{article}', 'ArticleController@update');
Route::delete('articles/{article}', 'ArticleController@delete');
class ArticleController extends Controller
{
    public function index()
    {
        return Article::all();
    }

    public function show(Article $article)
    {
        return $article;
    }

    public function store(Request $request)
    {
        $article = Article::create($request->all());

        return response()->json($article, 201);
    }

    public function update(Request $request, Article $article)
    {
        $article->update($request->all());

        return response()->json($article, 200);
    }

    public function delete(Article $article)
    {
        $article->delete();

        return response()->json(null, 204);
    }
}

A Note on HTTP Status Codes and the Response Format

We’ve also added the response()->json() call to our endpoints. This lets us explicitly return JSON data as well as send an HTTP code that can be parsed by the client. The most common codes you’ll be returning will be:

  • 200: OK. The standard success code and default option.
  • 201: Object created. Useful for the store actions.
  • 204: No content. When an action was executed successfully, but there is no content to return.
  • 206: Partial content. Useful when you have to return a paginated list of resources.
  • 400: Bad request. The standard option for requests that fail to pass validation.
  • 401: Unauthorized. The user needs to be authenticated.
  • 403: Forbidden. The user is authenticated, but does not have the permissions to perform an action.
  • 404: Not found. This will be returned automatically by Laravel when the resource is not found.
  • 500: Internal server error. Ideally you’re not going to be explicitly returning this, but if something unexpected breaks, this is what your user is going to receive.
  • 503: Service unavailable. Pretty self explanatory, but also another code that is not going to be returned explicitly by the application.

Sending a Correct 404 Response

If you tried to fetch a non-existent resource, you’ll be thrown an exception and you’ll receive the whole stacktrace, like this:

NotFoundHttpException Stacktrace

We can fix that by editing our exception handler class, located in app/Exceptions/Handler.php, to return a JSON response:

public function render($request, Exception $exception)
{
    // This will replace our 404 response with
    // a JSON response.
    if ($exception instanceof ModelNotFoundException) {
        return response()->json([
            'error' => 'Resource not found'
        ], 404);
    }

    return parent::render($request, $exception);
}

Here’s an example of the return:

{
    data: "Resource not found"
}

If you’re using Laravel to serve other pages, you have to edit the code to work with the Accept header, otherwise 404 errors from regular requests will return a JSON as well.

public function render($request, Exception $exception)
{
    // This will replace our 404 response with
    // a JSON response.
    if ($exception instanceof ModelNotFoundException &&
        $request->wantsJson())
    {
        return response()->json([
            'data' => 'Resource not found'
        ], 404);
    }

    return parent::render($request, $exception);
}

In this case, the API requests will need the header Accept: application/json.

Authentication

There are many ways to implement API Authentication in Laravel (one of them being Passport, a great way to implement OAuth2), but in this article, we’ll take a very simplified approach.

To get started, we’ll need to add an api_token field to the users table:

$ php artisan make:migration --table=users adds_api_token_to_users_table

And then implement the migration:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->string('api_token', 60)->unique()->nullable();
    });
}

public function down()
{
    Schema::table('users', function (Blueprint $table) {
        $table->dropColumn(['api_token']);
    });
}

After that, just run the migration using:

$ php artisan migrate

Creating the Register Endpoint

We’ll make use of the RegisterController (in the Auth folder) to return the correct response upon registration. Laravel comes with authentication out of the box, but we still need to tweak it a bit to return the response we want.

If APIs were in English, this is what an api authentication conversation would sound like

The controller makes use of the trait RegistersUsers to implement the registration. Here’s how it works:

public function register(Request $request)
{
    // Here the request is validated. The validator method is located
    // inside the RegisterController, and makes sure the name, email
    // password and password_confirmation fields are required.
    $this->validator($request->all())->validate();

    // A Registered event is created and will trigger any relevant
    // observers, such as sending a confirmation email or any 
    // code that needs to be run as soon as the user is created.
    event(new Registered($user = $this->create($request->all())));

    // After the user is created, he's logged in.
    $this->guard()->login($user);

    // And finally this is the hook that we want. If there is no
    // registered() method or it returns null, redirect him to
    // some other URL. In our case, we just need to implement
    // that method to return the correct response.
    return $this->registered($request, $user)
                    ?: redirect($this->redirectPath());
}

We just need to implement the registered() method in our RegisterController. The method receives the $request and the $user, so that’s really all we want. Here’s how the method should look like inside the controller:

protected function registered(Request $request, $user)
{
    $user->generateToken();

    return response()->json(['data' => $user->toArray()], 201);
}

And we can link it on the routes file:

Route::post(register, 'Auth\RegisterController@register);

In the section above, we used a method on the User model to generate the token. This is useful so that we only have a single way of generating the tokens. Add the following method to your User model:

class User extends Authenticatable
{
    ...
    public function generateToken()
    {
        $this->api_token = str_random(60);
        $this->save();

        return $this->api_token;
    }
}

And that’s it. The user is now registered and thanks to Laravel’s validation and out of the box authentication, the nameemailpassword, and password_confirmation fields are required, and the feedback is handled automatically. Checkout the validator() method inside the RegisterController to see how the rules are implemented.

Here’s what we get when we hit that endpoint:

$ curl -X POST http://localhost:8000/api/register \
 -H "Accept: application/json" \
 -H "Content-Type: application/json" \
 -d '{"name": "John", "email": "john.doe@toptal.com", "password": "toptal123", "password_confirmation": "toptal123"}'
{
    "data": {
        "api_token":"0syHnl0Y9jOIfszq11EC2CBQwCfObmvscrZYo5o2ilZPnohvndH797nDNyAT",
        "created_at": "2017-06-20 21:17:15",
        "email": "john.doe@toptal.com",
        "id": 51,
        "name": "John",
        "updated_at": "2017-06-20 21:17:15"
    }
}

Creating a Login Endpoint

Just like the registration endpoint, we can edit the LoginController (in the Auth folder) to support our API authentication. The login method of the AuthenticatesUsers trait can be overridden to support our API:

public function login(Request $request)
{
    $this->validateLogin($request);

    if ($this->attemptLogin($request)) {
        $user = $this->guard()->user();
        $user->generateToken();

        return response()->json([
            'data' => $user->toArray(),
        ]);
    }

    return $this->sendFailedLoginResponse($request);
}

And we can link it on the routes file:

Route::post('login', 'Auth\LoginController@login');

Now, assuming the seeders have been run, here’s what we get when we send a POST request to that route:

$ curl -X POST localhost:8000/api/login \
  -H "Accept: application/json" \
  -H "Content-type: application/json" \
  -d "{\"email\": \"admin@test.com\", \"password\": \"toptal\" }"
{
    "data": {
        "id":1,
        "name":"Administrator",
        "email":"admin@test.com",
        "created_at":"2017-04-25 01:05:34",
        "updated_at":"2017-04-25 02:50:40",
        "api_token":"Jll7q0BSijLOrzaOSm5Dr5hW9cJRZAJKOzvDlxjKCXepwAeZ7JR6YP5zQqnw"
    }
}

To send the token in a request, you can do it by sending an attribute api_token in the payload or as a bearer token in the request headers in the form of Authorization: Bearer Jll7q0BSijLOrzaOSm5Dr5hW9cJRZAJKOzvDlxjKCXepwAeZ7JR6YP5zQqnw.

Logging Out

With our current strategy, if the token is wrong or missing, the user should receive an unauthenticated response (which we’ll implement in the next section). So for a simple logout endpoint, we’ll send in the token and it will be removed on the database.

routes/api.php:

Route::post('logout', 'Auth\LoginController@logout');

Auth\LoginController.php:

public function logout(Request $request)
{
    $user = Auth::guard('api')->user();

    if ($user) {
        $user->api_token = null;
        $user->save();
    }

    return response()->json(['data' => 'User logged out.'], 200);
}

Using this strategy, whatever token the user has will be invalid, and the API will deny access (using middlewares, as explained in the next section). This needs to be coordinated with the front-end to avoid the user remaining logged without having access to any content.

Using Middlewares to Restrict Access

With the api_token created, we can toggle the authentication middleware in the routes file:

Route::middleware('auth:api')
    ->get('/user', function (Request $request) {
        return $request->user();
    });

We can access the current user using the $request->user() method or through the Auth facade

Auth::guard('api')->user(); // instance of the logged user
Auth::guard('api')->check(); // if a user is authenticated
Auth::guard('api')->id(); // the id of the authenticated user

And we get a result like this:

An InvalidArgumentException Stacktrace

This is because we need to edit the current unauthenticated method on our Handler class. The current version returns a JSON only if the request has the Accept: application/json header, so let’s change it:

protected function unauthenticated($request, AuthenticationException $exception)
{
    return response()->json(['error' => 'Unauthenticated'], 401);
}

With that fixed, we can go back to the article endpoints to wrap them in the auth:api middleware. We can do that by using route groups:

Route::group(['middleware' => 'auth:api'], function() {
    Route::get('articles', 'ArticleController@index');
    Route::get('articles/{article}', 'ArticleController@show');
    Route::post('articles', 'ArticleController@store');
    Route::put('articles/{article}', 'ArticleController@update');
    Route::delete('articles/{article}', 'ArticleController@delete');
});

This way we don’t have to set the middleware for each of the routes. It doesn’t save a lot of time right now, but as the project grows it helps to keep the routes DRY.

Testing Our Endpoints

Laravel includes integration with PHPUnit out of the box with a phpunit.xml already set up. The framework also provides us with several helpers and extra assertions that makes our lives much easier, especially for testing APIs.

There are a number of external tools you can use to test your API; however, testing inside Laravel is a much better alternative—we can have all the benefits of testing an API structure and results while retaining full control of the database. For the list endpoint, for example, we could run a couple of factories and assert the response contains those resources.

To get started, we’ll need to tweak a few settings to use an in-memory SQLite database. Using that will make our tests run lightning fast, but the trade-off is that some migration commands (constraints, for example) will not work properly in that particular setup. I advise moving away from SQLite in testing when you start getting migration errors or if you prefer a stronger set of tests instead of performant runs.

We’ll also run the migrations before each test. This setup will allow us to build the database for each test and then destroy it, avoiding any type of dependency between tests.

In our config/database.php file, we’ll need to set up the database field in the sqlite configuration to :memory::

...
'connections' => [

    'sqlite' => [
        'driver' => 'sqlite',
        'database' => ':memory:',
        'prefix' => '',
    ],
    
    ...
]

Then enable SQLite in phpunit.xml by adding the environment variable DB_CONNECTION:

    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="DB_CONNECTION" value="sqlite"/>
    </php>

With that out of the way, all that’s left is configuring our base TestCase class to use migrations and seed the database before each test. To do so, we need to add the DatabaseMigrations trait, and then add an Artisancall on our setUp() method. Here’s the class after the changes:

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\Artisan;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication, DatabaseMigrations;

    public function setUp()
    {
        parent::setUp();
        Artisan::call('db:seed');
    }
}

One last thing that I like to do is to add the test command to composer.json:

    "scripts": {
        "test" : [
            "vendor/bin/phpunit"
        ],
    ... 
    },    

The test command will be available like this:

$ composer test

Setting Up Factories for Our Tests

Factories will allow us to quickly create objects with the right data for testing. They’re located in the database/factories folder. Laravel comes out of the box with a factory for the User class, so let’s add one for the Article class:

$factory->define(App\Article::class, function (Faker\Generator $faker) {
    return [
        'title' => $faker->sentence,
        'body' => $faker->paragraph,
    ];
});

The Faker library is already injected to help us create the correct format of random data for our models.

Our First Tests

We can use Laravel’s assert methods to easily hit an endpoint and evaluate its response. Let’s create our first test, the login test, using the following command:

$ php artisan make:test Feature/LoginTest

And here is our test:

class LoginTest extends TestCase
{
    public function testRequiresEmailAndLogin()
    {
        $this->json('POST', 'api/login')
            ->assertStatus(422)
            ->assertJson([
                'email' => ['The email field is required.'],
                'password' => ['The password field is required.'],
            ]);
    }


    public function testUserLoginsSuccessfully()
    {
        $user = factory(User::class)->create([
            'email' => 'testlogin@user.com',
            'password' => bcrypt('toptal123'),
        ]);

        $payload = ['email' => 'testlogin@user.com', 'password' => 'toptal123'];

        $this->json('POST', 'api/login', $payload)
            ->assertStatus(200)
            ->assertJsonStructure([
                'data' => [
                    'id',
                    'name',
                    'email',
                    'created_at',
                    'updated_at',
                    'api_token',
                ],
            ]);

    }
}

These methods test a couple of simple cases. The json() method hits the endpoint and the other asserts are pretty self explanatory. One detail about assertJson(): this method converts the response into an array searches for the argument, so the order is important. You can chain multiple assertJson() calls in that case.

Now, let’s create the register endpoint test and write a couple for that endpoint:

$ php artisan make:test RegisterTest
class RegisterTest extends TestCase
{
    public function testsRegistersSuccessfully()
    {
        $payload = [
            'name' => 'John',
            'email' => 'john@toptal.com',
            'password' => 'toptal123',
            'password_confirmation' => 'toptal123',
        ];

        $this->json('post', '/api/register', $payload)
            ->assertStatus(201)
            ->assertJsonStructure([
                'data' => [
                    'id',
                    'name',
                    'email',
                    'created_at',
                    'updated_at',
                    'api_token',
                ],
            ]);;
    }

    public function testsRequiresPasswordEmailAndName()
    {
        $this->json('post', '/api/register')
            ->assertStatus(422)
            ->assertJson([
                'name' => ['The name field is required.'],
                'email' => ['The email field is required.'],
                'password' => ['The password field is required.'],
            ]);
    }

    public function testsRequirePasswordConfirmation()
    {
        $payload = [
            'name' => 'John',
            'email' => 'john@toptal.com',
            'password' => 'toptal123',
        ];

        $this->json('post', '/api/register', $payload)
            ->assertStatus(422)
            ->assertJson([
                'password' => ['The password confirmation does not match.'],
            ]);
    }
}

And lastly, the logout endpoint:

$ php artisan make:test LogoutTest
class LogoutTest extends TestCase
{
    public function testUserIsLoggedOutProperly()
    {
        $user = factory(User::class)->create(['email' => 'user@test.com']);
        $token = $user->generateToken();
        $headers = ['Authorization' => "Bearer $token"];

        $this->json('get', '/api/articles', [], $headers)->assertStatus(200);
        $this->json('post', '/api/logout', [], $headers)->assertStatus(200);

        $user = User::find($user->id);

        $this->assertEquals(null, $user->api_token);
    }

    public function testUserWithNullToken()
    {
        // Simulating login
        $user = factory(User::class)->create(['email' => 'user@test.com']);
        $token = $user->generateToken();
        $headers = ['Authorization' => "Bearer $token"];

        // Simulating logout
        $user->api_token = null;
        $user->save();

        $this->json('get', '/api/articles', [], $headers)->assertStatus(401);
    }
}

It’s important to note that, during testing, the Laravel application is not instantiated again on a new request. Which means that when we hit the authentication middleware, it saves the current user inside the TokenGuard instance to avoid hitting the database again. A wise choice, however—in this case, it means we have to split the logout test into two, to avoid any issues with the previously cached user.

Testing the Article endpoints is straightforward as well:

class ArticleTest extends TestCase
{
    public function testsArticlesAreCreatedCorrectly()
    {
        $user = factory(User::class)->create();
        $token = $user->generateToken();
        $headers = ['Authorization' => "Bearer $token"];
        $payload = [
            'title' => 'Lorem',
            'body' => 'Ipsum',
        ];

        $this->json('POST', '/api/articles', $payload, $headers)
            ->assertStatus(200)
            ->assertJson(['id' => 1, 'title' => 'Lorem', 'body' => 'Ipsum']);
    }

    public function testsArticlesAreUpdatedCorrectly()
    {
        $user = factory(User::class)->create();
        $token = $user->generateToken();
        $headers = ['Authorization' => "Bearer $token"];
        $article = factory(Article::class)->create([
            'title' => 'First Article',
            'body' => 'First Body',
        ]);

        $payload = [
            'title' => 'Lorem',
            'body' => 'Ipsum',
        ];

        $response = $this->json('PUT', '/api/articles/' . $article->id, $payload, $headers)
            ->assertStatus(200)
            ->assertJson([ 
                'id' => 1, 
                'title' => 'Lorem', 
                'body' => 'Ipsum' 
            ]);
    }

    public function testsArtilcesAreDeletedCorrectly()
    {
        $user = factory(User::class)->create();
        $token = $user->generateToken();
        $headers = ['Authorization' => "Bearer $token"];
        $article = factory(Article::class)->create([
            'title' => 'First Article',
            'body' => 'First Body',
        ]);

        $this->json('DELETE', '/api/articles/' . $article->id, [], $headers)
            ->assertStatus(204);
    }

    public function testArticlesAreListedCorrectly()
    {
        factory(Article::class)->create([
            'title' => 'First Article',
            'body' => 'First Body'
        ]);

        factory(Article::class)->create([
            'title' => 'Second Article',
            'body' => 'Second Body'
        ]);

        $user = factory(User::class)->create();
        $token = $user->generateToken();
        $headers = ['Authorization' => "Bearer $token"];

        $response = $this->json('GET', '/api/articles', [], $headers)
            ->assertStatus(200)
            ->assertJson([
                [ 'title' => 'First Article', 'body' => 'First Body' ],
                [ 'title' => 'Second Article', 'body' => 'Second Body' ]
            ])
            ->assertJsonStructure([
                '*' => ['id', 'body', 'title', 'created_at', 'updated_at'],
            ]);
    }

}

Next Steps

That’s all there is to it. There’s definitely room for improvement—you can implement OAuth2 with the Passportpackage, integrate a pagination and transformation layer (I recommend Fractal), the list goes on—but I wanted to go through the basics of creating and testing an API in Laravel with no external packages.

Laravel has certainly improved my experience with PHP and the ease of testing with it has solidified my interest in the framework. It’s not perfect, but it’s flexible enough to let you work around its issues.

If you’re designing a public API, check out 5 Golden Rules for Great Web API Design.

This article is written by André Castelo and originally posted at Toptal

About the Author: André Castelo is a web developer focused on PHP and JavaScript with experience developing apps with Laravel and CodeIgniter as well as APIs in Laravel and client-side single-page apps using AngularJS. He's equally comfortable working with a team or flying solo.

What is AngularJS?

AngularJS is a JavaScript MVC framework developed by Google that lets you build well structured, easily testable, and maintainable front-end applications.

And Why Should I Use It?

If you haven’t tried AngularJS yet, you’re missing out. The framework consists of a tightly integrated toolset that will help you build well structured, rich client-side applications in a modular fashion—with less code and more flexibility.

AngularJS extends HTML by providing directives that add functionality to your markup and allow you to create powerful dynamic templates. You can also create your own directives, crafting reusable components that fill your needs and abstracting away all the DOM manipulation logic.

It also implements two-way data binding, connecting your HTML (views) to your JavaScript objects (models) seamlessly. In simple terms, this means that any update on your model will be immediately reflected in your view without the need for any DOM manipulation or event handling (e.g., with jQuery).

Angular provides services on top of XHR that dramatically simplify your code and allow you to abstract API calls into reusable services. With that, you can move your model and business logic to the front-end and build back-end agnostic web apps.

Finally, I love Angular because of its flexibility regarding server communication. Like most JavaScript MVC frameworks, it lets you work with any server-side technology as long as it can serve your app through a RESTful web API. But Angular also provides services on top of XHR that dramatically simplify your code and allow you to abstract API calls into reusable services. As a result, you can move your model and business logic to the front-end and build back-end agnostic web apps. In this post, we’ll do just that, one step at a time.

So, Where Do I Begin?

First, let’s decide the nature of the app we want to build. In this guide, we’d prefer not to spend too much time on the back-end, so we’ll write something based on data that’s easily attainable on the Internet—like a sports feed app!

Since I happen to be a huge fan of motor racing and Formula 1, I’ll use an autosport API service to act as our back-end. Luckily, the guys at Ergast are kind enough to provide a free motorsport API that will be perfect for us.

For a sneak peak at what we’re going to build, take a look at the live demo. To prettify the demo and show off some Angular templating, I applied a Bootstrap theme from WrapBootstrap, but seeing as this article isn’t about CSS, I’ll just abstract it away from the examples and leave it out.

Getting Started Tutorial

Let’s kickstart our example app with some boilerplate. I recommend the angular-seed project as it not only provides you with a great skeleton for bootstrapping, but also sets the ground for unit testing with Karma and Jasmine (we won’t be doing any testing in this demo, so we’ll just leave that stuff aside for now; see Part 2 of this tutorial for more info on setting up your project for unit and end-to-end testing).

EDIT (May 2014): Since I wrote this tutorial, the angular-seed project has gone through some heavy changes (including the additon of Bower as package manager). If you have any doubts about how to deploy the project, take a quick look at the first section of their reference guide. In Part 2 of ths tutorial, Bower, among other tools, is covered in greater detail.

OK, now that we’ve cloned the repository and installed the dependencies, our app’s skeleton will look like this:

angularjs tutorial - start with the skeleton

Now we can start coding. As we’re trying to build a sports feed for a racing championship, let’s begin with the most relevant view: the championship table.

the championship table

Given that we already have a drivers list defined within our scope (hang with me – we’ll get there), and ignoring any CSS (for readability), our HTML might look like:

<body ng-app="F1FeederApp" ng-controller="driversController">
  <table>
    <thead>
      <tr><th colspan="4">Drivers Championship Standings</th></tr>
    </thead>
    <tbody>
      <tr ng-repeat="driver in driversList">
        <td>{{$index + 1}}</td>
        <td>
          <img src="img/flags/{{driver.Driver.nationality}}.png" />
          {{driver.Driver.givenName}}&nbsp;{{driver.Driver.familyName}}
        </td>
        <td>{{driver.Constructors[0].name}}</td>
        <td>{{driver.points}}</td>
      </tr>
    </tbody>
  </table>
</body>

The first thing you’ll notice in this template is the use of expressions (“{{“ and “}}”) to return variable values. In AngularJS, expressions allow you to execute some computation in order to return a desired value. Some valid expressions would be:

  • {{ 1 + 1 }}
  • {{ 946757880 | date }}
  • {{ user.name }}

Effectively, expressions are JavaScript-like snippets. But despite being very powerful, you shouldn’t use expressions to implement any higher-level logic. For that, we use directives.

Understanding Basic Directives

The second thing you’ll notice is the presence of ng-attributes, which you wouldn’t see in typical markup. Those are directives.

At a high level, directives are markers (such as attributes, tags, and class names) that tell AngularJS to attach a given behaviour to a DOM element (or transform it, replace it, etc.). Let’s take a look at the ones we’ve seen already:

  • The ng-app directive is responsible for bootstrapping your app defining its scope. In AngularJS, you can have multiple apps within the same page, so this directive defines where each distinct app starts and ends.
  • The ng-controller directive defines which controller will be in charge of your view. In this case, we denote the driversController, which will provide our list of drivers (driversList).
  • The ng-repeat directive is one of the most commonly used and serves to define your template scope when looping through collections. In the example above, it replicates a line in the table for each driver in driversList.

Adding Controllers

Of course, there’s no use for our view without a controller. Let’s add driversController to our controllers.js:

angular.module('F1FeederApp.controllers', []).
controller('driversController', function($scope) {
    $scope.driversList = [
      {
          Driver: {
              givenName: 'Sebastian',
              familyName: 'Vettel'
          },
          points: 322,
          nationality: "German",
          Constructors: [
              {name: "Red Bull"}
          ]
      },
      {
          Driver: {
          givenName: 'Fernando',
              familyName: 'Alonso'
          },
          points: 207,
          nationality: "Spanish",
          Constructors: [
              {name: "Ferrari"}
          ]
      }
    ];
});

You may have noticed the $scope variable we’re passing as a parameter to the controller. The $scopevariable is supposed to link your controller and views. In particular, it holds all the data that will be used within your template. Anything you add to it (like the driversList in the above example) will be directly accessible in your views. For now, let’s just work with a dummy (static) data array, which we will replace later with our API service.

Now, add this to app.js:

angular.module('F1FeederApp', [
  'F1FeederApp.controllers'
]);

With this line of code, we actually initialize our app and register the modules on which it depends. We’ll come back to that file (app.js) later on.

Now, let’s put everything together in index.html:

<!DOCTYPE html>
<html>
<head>
  <title>F-1 Feeder</title>
</head>

<body ng-app="F1FeederApp" ng-controller="driversController">
  <table>
    <thead>
      <tr><th colspan="4">Drivers Championship Standings</th></tr>
    </thead>
    <tbody>
      <tr ng-repeat="driver in driversList">
        <td>{{$index + 1}}</td>
        <td>
          <img src="img/flags/{{driver.Driver.nationality}}.png" />
          {{driver.Driver.givenName}}&nbsp;{{driver.Driver.familyName}}
        </td>
        <td>{{driver.Constructors[0].name}}</td>
        <td>{{driver.points}}</td>
      </tr>
    </tbody>
  </table>
  <script src="bower_components/angular/angular.js"></script>
  <script src="bower_components/angular-route/angular-route.js"></script>
  <script src="js/app.js"></script>
  <script src="js/services.js"></script>
  <script src="js/controllers.js"></script>
</body>
</html>

Modulo minor mistakes, you can now boot up your app and check your (static) list of drivers.

Note: If you need help debugging your app and visualizing your models and scope within the browser, I recommend taking a look at the awesome Batarang plugin for Chrome.

Loading Data From the Server

Since we already know how to display our controller’s data in our view, it’s time to actually fetch live data from a RESTful server.

To facilitate communication with HTTP servers, AngularJS provides the $http and $resource services. The former is but a layer on top of XMLHttpRequest or JSONP, while the latter provides a higher level of abstraction. We’ll use $http.

To abstract our server API calls from the controller, let’s create our own custom service which will fetch our data and act as a wrapper around $http by adding this to our services.js:

angular.module('F1FeederApp.services', []).
  factory('ergastAPIservice', function($http) {

    var ergastAPI = {};

    ergastAPI.getDrivers = function() {
      return $http({
        method: 'JSONP', 
        url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK'
      });
    }

    return ergastAPI;
  });

With the first two lines, we create a new module (F1FeederApp.services) and register a service within that module (ergastAPIservice). Notice that we pass $http as a parameter to that service. This tells Angular’s dependency injection engine that our new service requires (or depends on) the $http service.

In a similar fashion, we need to tell Angular to include our new module into our app. Let’s register it with app.js, replacing our existing code with:

angular.module('F1FeederApp', [
  'F1FeederApp.controllers',
  'F1FeederApp.services'
]);

Now, all we need to do is tweak our controller.js a bit, include ergastAPIservice as a dependency, and we’ll be good to go:

angular.module('F1FeederApp.controllers', []).
  controller('driversController', function($scope, ergastAPIservice) {
    $scope.nameFilter = null;
    $scope.driversList = [];

    ergastAPIservice.getDrivers().success(function (response) {
        //Dig into the responde to get the relevant data
        $scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings;
    });
  });

Now reload the app and check out the result. Notice that we didn’t make any changes to our template, but we added a nameFilter variable to our scope. Let’s put that variable to use.

Filters

Great! We have a functional controller. But it only shows a list of drivers. Let’s add some functionality by implementing a simple text search input which will filter our list. Let’s add the following line to our index.html, right below the <body> tag:

<input type="text" ng-model="nameFilter" placeholder="Search..."/>

We are now making use of the ng-model directive. This directive binds our text field to the $scope.nameFiltervariable and makes sure that its value is always up-to-date with the input value. Now, let’s visit index.html one more time and make a small adjustment to the line that contains the ng-repeat directive:

<tr ng-repeat="driver in driversList | filter: nameFilter">

This line tells ng-repeat that, before outputting the data, the driversList array must be filtered by the value stored in nameFilter.

At this point, two-way data binding kicks in: every time a value is input in the search field, Angular immediately ensures that the $scope.nameFilter that we associated with it is updated with the new value. Since the binding works both ways, the moment the nameFilter value is updated, the second directive associated to it (i.e., the ng-repeat) also gets the new value and the view is updated immediately.

Reload the app and check out the search bar.

app search bar

Notice that this filter will look for the keyword on all attributes of the model, including the ones we´re not using. Let’s say we only want to filter by Driver.givenName and Driver.familyName: First, we add to driversController, right below the $scope.driversList = []; line:

$scope.searchFilter = function (driver) {
    var keyword = new RegExp($scope.nameFilter, 'i');
    return !$scope.nameFilter || keyword.test(driver.Driver.givenName) || keyword.test(driver.Driver.familyName);
};

Now, back to index.html, we update the line that contains the ng-repeat directive:

<tr ng-repeat="driver in driversList | filter: searchFilter">

Reload the app one more time and now we have a search by name.

Routes

Our next goal is to create a driver details page which will let us click on each driver and see his/her career details.

First, let’s include the $routeProvider service (in app.js) which will help us deal with these varied application routes. Then, we’ll add two such routes: one for the championship table and another for the driver details. Here’s our new app.js:

angular.module('F1FeederApp', [
  'F1FeederApp.services',
  'F1FeederApp.controllers',
  'ngRoute'
]).
config(['$routeProvider', function($routeProvider) {
  $routeProvider.
	when("/drivers", {templateUrl: "partials/drivers.html", controller: "driversController"}).
	when("/drivers/:id", {templateUrl: "partials/driver.html", controller: "driverController"}).
	otherwise({redirectTo: '/drivers'});
}]);

With that change, navigating to http://domain/#/drivers will load the driversController and look for the partial view to render in partials/drivers.html. But wait! We don’t have any partial views yet, right? We’ll need to create those too.

Partial Views

AngularJS will allow you to bind your routes to specific controllers and views.

But first, we need to tell Angular where to render these partial views. For that, we’ll use the ng-view directive, modifying our index.html to mirror the following:

<!DOCTYPE html>
<html>
<head>
  <title>F-1 Feeder</title>
</head>

<body ng-app="F1FeederApp">
  <ng-view></ng-view>
  <script src="bower_components/angular/angular.js"></script>
  <script src="bower_components/angular-route/angular-route.js"></script>
  <script src="js/app.js"></script>
  <script src="js/services.js"></script>
  <script src="js/controllers.js"></script>
</body>
</html>

Now, whenever we navigate through our app routes, Angular will load the associated view and render it in place of the <ng-view> tag. All we need to do is create a file named partials/drivers.html and put our championship table HTML there. We’ll also use this chance to link the driver name to our driver details route:

<input type="text" ng-model="nameFilter" placeholder="Search..."/>
<table>
<thead>
  <tr><th colspan="4">Drivers Championship Standings</th></tr>
</thead>
<tbody>
  <tr ng-repeat="driver in driversList | filter: searchFilter">
    <td>{{$index + 1}}</td>
    <td>
      <img src="img/flags/{{driver.Driver.nationality}}.png" />
      <a href="#/drivers/{{driver.Driver.driverId}}">
	  	{{driver.Driver.givenName}}&nbsp;{{driver.Driver.familyName}}
	  </a>
	</td>
    <td>{{driver.Constructors[0].name}}</td>
    <td>{{driver.points}}</td>
  </tr>
</tbody>
</table>

Finally, let’s decide what we want to show in the details page. How about a summary of all the relevant facts about the driver (e.g., birth, nationality) along with a table containing his/her recent results? To do that, we add to services.js:

angular.module('F1FeederApp.services', [])
  .factory('ergastAPIservice', function($http) {

    var ergastAPI = {};

    ergastAPI.getDrivers = function() {
      return $http({
        method: 'JSONP', 
        url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK'
      });
    }

    ergastAPI.getDriverDetails = function(id) {
      return $http({
        method: 'JSONP', 
        url: 'http://ergast.com/api/f1/2013/drivers/'+ id +'/driverStandings.json?callback=JSON_CALLBACK'
      });
    }

    ergastAPI.getDriverRaces = function(id) {
      return $http({
        method: 'JSONP', 
        url: 'http://ergast.com/api/f1/2013/drivers/'+ id +'/results.json?callback=JSON_CALLBACK'
      });
    }

    return ergastAPI;
  });

This time, we provide the driver’s ID to the service so that we retrieve the information relevant solely to a specific driver. Now, we modify controllers.js:

angular.module('F1FeederApp.controllers', []).

  /* Drivers controller */
  controller('driversController', function($scope, ergastAPIservice) {
    $scope.nameFilter = null;
    $scope.driversList = [];
    $scope.searchFilter = function (driver) {
        var re = new RegExp($scope.nameFilter, 'i');
        return !$scope.nameFilter || re.test(driver.Driver.givenName) || re.test(driver.Driver.familyName);
    };

    ergastAPIservice.getDrivers().success(function (response) {
        //Digging into the response to get the relevant data
        $scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings;
    });
  }).

  /* Driver controller */
  controller('driverController', function($scope, $routeParams, ergastAPIservice) {
    $scope.id = $routeParams.id;
    $scope.races = [];
    $scope.driver = null;

    ergastAPIservice.getDriverDetails($scope.id).success(function (response) {
        $scope.driver = response.MRData.StandingsTable.StandingsLists[0].DriverStandings[0]; 
    });

    ergastAPIservice.getDriverRaces($scope.id).success(function (response) {
        $scope.races = response.MRData.RaceTable.Races; 
    }); 
  });

The important thing to notice here is that we just injected the $routeParams service into the driver controller. This service will allow us to access our URL parameters (for the :id, in this case) using $routeParams.id.

Now that we have our data in the scope, we only need the remaining partial view. Let’s create a file named partials/driver.html and add:

<section id="main">
  <a href="./#/drivers"><- Back to drivers list</a>
  <nav id="secondary" class="main-nav">
    <div class="driver-picture">
      <div class="avatar">
        <img ng-show="driver" src="img/drivers/{{driver.Driver.driverId}}.png" />
        <img ng-show="driver" src="img/flags/{{driver.Driver.nationality}}.png" /><br/>
        {{driver.Driver.givenName}} {{driver.Driver.familyName}}
      </div>
    </div>
    <div class="driver-status">
      Country: {{driver.Driver.nationality}}   <br/>
      Team: {{driver.Constructors[0].name}}<br/>
      Birth: {{driver.Driver.dateOfBirth}}<br/>
      <a href="{{driver.Driver.url}}" target="_blank">Biography</a>
    </div>
  </nav>

  <div class="main-content">
    <table class="result-table">
      <thead>
        <tr><th colspan="5">Formula 1 2013 Results</th></tr>
      </thead>
      <tbody>
        <tr>
          <td>Round</td> <td>Grand Prix</td> <td>Team</td> <td>Grid</td> <td>Race</td>
        </tr>
        <tr ng-repeat="race in races">
          <td>{{race.round}}</td>
          <td><img  src="img/flags/{{race.Circuit.Location.country}}.png" />{{race.raceName}}</td>
          <td>{{race.Results[0].Constructor.name}}</td>
          <td>{{race.Results[0].grid}}</td>
          <td>{{race.Results[0].position}}</td>
        </tr>
      </tbody>
    </table>
  </div>

</section>

Notice that we’re now putting the ng-show directive to good use. This directive will only show the HTML element if the expression provided is true (i.e., neither false, nor null). In this case, the avatar will only show up once the driver object has been loaded into the scope by the controller.

Finishing Touches

Add in a bunch of CSS and render your page. You should end up with something like this:

page rendered with CSS

You’re now ready to fire up your app and make sure both routes are working as desired. You could also add a static menu to index.html to improve the user’s navigation capabilities. The possibilities are endless.

EDIT (May 2014): I’ve received many requests for a downloadable version of the code that we build in this tutorial. I’ve therefore decided to release it here (stripped of any CSS). However, I really do not recommend downloading it, since this guide contains every single step you need to build the same application with your own hands, which will be a much more useful and effective learning exercise.

This article is written by Raoni Boaventura and originally published at Toptal

About the author:  Raoni is an experienced software developer and who has contributed to a wealth of projects using Ruby on Rails, JavaScript, and PHP on top of many other programming languages and frameworks. He is an excellent problem solver, and a great communicator as both a team member and a team lead.

Machine Learning (ML) is coming into its own, with a growing recognition that ML can play a key role in a wide range of critical applications, such as data mining, natural language processing, image recognition, and expert systems. ML provides potential solutions in all these domains and more, and is set to be a pillar of our future civilization.

The supply of able ML designers has yet to catch up to this demand. A major reason for this is that ML is just plain tricky. This Machine Learning tutorial introduces the basics of ML theory, laying down the common themes and concepts, making it easy to follow the logic and get comfortable with machine learning basics.

Machine learning tutorial illustration: This curious machine is learning machine learning, unsupervised.

What is Machine Learning?

So what exactly is “machine learning” anyway? ML is actually a lot of things. The field is quite vast and is expanding rapidly, being continually partitioned and sub-partitioned ad nauseam into different sub-specialties and types of machine learning.

There are some basic common threads, however, and the overarching theme is best summed up by this oft-quoted statement made by Arthur Samuel way back in 1959: “[Machine Learning is the] field of study that gives computers the ability to learn without being explicitly programmed.”

And more recently, in 1997, Tom Mitchell gave a “well-posed” definition that has proven more useful to engineering types: “A computer program is said to learn from experience E with respect to some task T and some performance measure P, if its performance on T, as measured by P, improves with experience E.”

“A computer program is said to learn from experience E with respect to some task T and some performance measure P, if its performance on T, as measured by P, improves with experience E.” — Tom Mitchell, Carnegie Mellon University

So if you want your program to predict, for example, traffic patterns at a busy intersection (task T), you can run it through a machine learning algorithm with data about past traffic patterns (experience E) and, if it has successfully “learned”, it will then do better at predicting future traffic patterns (performance measure P).

The highly complex nature of many real-world problems, though, often means that inventing specialized algorithms that will solve them perfectly every time is impractical, if not impossible. Examples of machine learning problems include, “Is this cancer?”“What is the market value of this house?”“Which of these people are good friends with each other?”“Will this rocket engine explode on take off?”“Will this person like this movie?”“Who is this?”“What did you say?”, and “How do you fly this thing?”. All of these problems are excellent targets for an ML project, and in fact ML has been applied to each of them with great success.

ML solves problems that cannot be solved by numerical means alone.

Among the different types of ML tasks, a crucial distinction is drawn between supervised and unsupervised learning:

  • Supervised machine learning: The program is “trained” on a pre-defined set of “training examples”, which then facilitate its ability to reach an accurate conclusion when given new data.
  • Unsupervised machine learning: The program is given a bunch of data and must find patterns and relationships therein.

We will primarily focus on supervised learning here, but the end of the article includes a brief discussion of unsupervised learning with some links for those who are interested in pursuing the topic further.

Supervised Machine Learning

In the majority of supervised learning applications, the ultimate goal is to develop a finely tuned predictor function h(x) (sometimes called the “hypothesis”). “Learning” consists of using sophisticated mathematical algorithms to optimize this function so that, given input data x about a certain domain (say, square footage of a house), it will accurately predict some interesting value h(x) (say, market price for said house).

In practice, x almost always represents multiple data points. So, for example, a housing price predictor might take not only square-footage (x1) but also number of bedrooms (x2), number of bathrooms (x3), number of floors (x4), year built (x5), zip code (x6), and so forth. Determining which inputs to use is an important part of ML design. However, for the sake of explanation, it is easiest to assume a single input value is used.

So let’s say our simple predictor has this form:

h of x equals theta 0 plus theta 1 times x

where theta 0 and theta 1 are constants. Our goal is to find the perfect values of theta 0 and theta 1 to make our predictor work as well as possible.

Optimizing the predictor h(x) is done using training examples. For each training example, we have an input value x_train, for which a corresponding output, y, is known in advance. For each example, we find the difference between the known, correct value y, and our predicted value h(x_train). With enough training examples, these differences give us a useful way to measure the “wrongness” of h(x). We can then tweak h(x) by tweaking the values of theta 0 and theta 1 to make it “less wrong”. This process is repeated over and over until the system has converged on the best values for theta 0 and theta 1. In this way, the predictor becomes trained, and is ready to do some real-world predicting.

Machine Learning Examples

We stick to simple problems in this post for the sake of illustration, but the reason ML exists is because, in the real world, the problems are much more complex. On this flat screen we can draw you a picture of, at most, a three-dimensional data set, but ML problems commonly deal with data with millions of dimensions, and very complex predictor functions. ML solves problems that cannot be solved by numerical means alone.

With that in mind, let’s look at a simple example. Say we have the following training data, wherein company employees have rated their satisfaction on a scale of 1 to 100:

Employee satisfaction rating by salary is a great machine learning example.

First, notice that the data is a little noisy. That is, while we can see that there is a pattern to it (i.e. employee satisfaction tends to go up as salary goes up), it does not all fit neatly on a straight line. This will always be the case with real-world data (and we absolutely want to train our machine using real-world data!). So then how can we train a machine to perfectly predict an employee’s level of satisfaction? The answer, of course, is that we can’t. The goal of ML is never to make “perfect” guesses, because ML deals in domains where there is no such thing. The goal is to make guesses that are good enough to be useful.

It is somewhat reminiscent of the famous statement by British mathematician and professor of statistics George E. P. Box that “all models are wrong, but some are useful”.

The goal of ML is never to make “perfect” guesses, because ML deals in domains where there is no such thing. The goal is to make guesses that are good enough to be useful.

Machine Learning builds heavily on statistics. For example, when we train our machine to learn, we have to give it a statistically significant random sample as training data. If the training set is not random, we run the risk of the machine learning patterns that aren’t actually there. And if the training set is too small (see law of large numbers), we won’t learn enough and may even reach inaccurate conclusions. For example, attempting to predict company-wide satisfaction patterns based on data from upper management alone would likely be error-prone.

With this understanding, let’s give our machine the data we’ve been given above and have it learn it. First we have to initialize our predictor h(x) with some reasonable values of theta 0 and theta 1. Now our predictor looks like this when placed over our training set:

h of x equals twelve plus 0 point two x Machine learning example illustration: A machine learning predictor over a training dataset.

If we ask this predictor for the satisfaction of an employee making $60k, it would predict a rating of 27:

In this image, the machine has yet to learn to predict a probable outcome.

It’s obvious that this was a terrible guess and that this machine doesn’t know very much.

So now, let’s give this predictor all the salaries from our training set, and take the differences between the resulting predicted satisfaction ratings and the actual satisfaction ratings of the corresponding employees. If we perform a little mathematical wizardry (which I will describe shortly), we can calculate, with very high certainty, that values of 13.12 for theta 0 and 0.61 for theta 1 are going to give us a better predictor.

h of x equals thirteen point one two plus 0 point six one x In this case, the machine learning predictor is getting closer.

And if we repeat this process, say 1500 times, our predictor will end up looking like this:

h of x equals fifteen point five four plus 0 point seven five x With a lot of repetition, the machine learning process starts to take shape.

At this point, if we repeat the process, we will find that theta 0 and theta 1 won’t change by any appreciable amount anymore and thus we see that the system has converged. If we haven’t made any mistakes, this means we’ve found the optimal predictor. Accordingly, if we now ask the machine again for the satisfaction rating of the employee who makes $60k, it will predict a rating of roughly 60.

In this example, the machine has learned to predict a probable data point.

Now we’re getting somewhere.

Machine Learning Regression: A Note on Complexity

The above example is technically a simple problem of univariate linear regression, which in reality can be solved by deriving a simple normal equation and skipping this “tuning” process altogether. However, consider a predictor that looks like this:

Four dimensional equation example

This function takes input in four dimensions and has a variety of polynomial terms. Deriving a normal equation for this function is a significant challenge. Many modern machine learning problems take thousands or even millions of dimensions of data to build predictions using hundreds of coefficients. Predicting how an organism’s genome will be expressed, or what the climate will be like in fifty years, are examples of such complex problems.

Many modern ML problems take thousands or even millions of dimensions of data to build predictions using hundreds of coefficients.

Fortunately, the iterative approach taken by ML systems is much more resilient in the face of such complexity. Instead of using brute force, a machine learning system “feels its way” to the answer. For big problems, this works much better. While this doesn’t mean that ML can solve all arbitrarily complex problems (it can’t), it does make for an incredibly flexible and powerful tool.

Gradient Descent – Minimizing “Wrongness”

Let’s take a closer look at how this iterative process works. In the above example, how do we make sure theta 0and theta 1 are getting better with each step, and not worse? The answer lies in our “measurement of wrongness” alluded to previously, along with a little calculus.

The wrongness measure is known as the cost function (a.k.a., loss function), J of theta. The input theta represents all of the coefficients we are using in our predictor. So in our case, theta is really the pair theta 0 and theta 1J of theta 0 and theta 1 gives us a mathematical measurement of how wrong our predictor is when it uses the given values of theta 0 and theta 1.

The choice of the cost function is another important piece of an ML program. In different contexts, being “wrong” can mean very different things. In our employee satisfaction example, the well-established standard is the linear least squares function:

Cost function expressed as a linear least squares function

With least squares, the penalty for a bad guess goes up quadratically with the difference between the guess and the correct answer, so it acts as a very “strict” measurement of wrongness. The cost function computes an average penalty over all of the training examples.

So now we see that our goal is to find theta 0 and theta 1 for our predictor h(x) such that our cost function J of theta 0 and theta 1 is as small as possible. We call on the power of calculus to accomplish this.

Consider the following plot of a cost function for some particular Machine Learning problem:

This graphic depicts the bowl-shaped plot of a cost function for a machine learning example.

Here we can see the cost associated with different values of theta 0 and theta 1. We can see the graph has a slight bowl to its shape. The bottom of the bowl represents the lowest cost our predictor can give us based on the given training data. The goal is to “roll down the hill”, and find theta 0 and theta 1 corresponding to this point.

This is where calculus comes in to this machine learning tutorial. For the sake of keeping this explanation manageable, I won’t write out the equations here, but essentially what we do is take the gradient of J of theta 0 and theta 1, which is the pair of derivatives of J of theta 0 and theta 1 (one over theta 0 and one over theta 1). The gradient will be different for every different value of theta 0 and theta 1, and tells us what the “slope of the hill is” and, in particular, “which way is down”, for these particular thetas. For example, when we plug our current values of theta into the gradient, it may tell us that adding a little to theta 0 and subtracting a little from theta 1 will take us in the direction of the cost function-valley floor. Therefore, we add a little to theta 0, and subtract a little from theta 1, and voilà! We have completed one round of our learning algorithm. Our updated predictor, h(x) = theta 0 + theta 1x, will return better predictions than before. Our machine is now a little bit smarter.

This process of alternating between calculating the current gradient, and updating the thetas from the results, is known as gradient descent.

This image depicts an example of a machine learning gradient descent. This image depicts the number of iterations for this machine learning tutorial.

That covers the basic theory underlying the majority of supervised Machine Learning systems. But the basic concepts can be applied in a variety of different ways, depending on the problem at hand.

Classification Problems in Machine Learning

Under supervised ML, two major subcategories are:

  • Regression machine learning systems: Systems where the value being predicted falls somewhere on a continuous spectrum. These systems help us with questions of “How much?” or “How many?”.
  • Classification machine learning systems: Systems where we seek a yes-or-no prediction, such as “Is this tumer cancerous?”, “Does this cookie meet our quality standards?”, and so on.

As it turns out, the underlying Machine Learning theory is more or less the same. The major differences are the design of the predictor h(x) and the design of the cost function J of theta.

Our examples so far have focused on regression problems, so let’s now also take a look at a classification example.

Here are the results of a cookie quality testing study, where the training examples have all been labeled as either “good cookie” (y = 1) in blue or “bad cookie” (y = 0) in red.

This example shows how a machine learning regression predictor is not the right solution here.

In classification, a regression predictor is not very useful. What we usually want is a predictor that makes a guess somewhere between 0 and 1. In a cookie quality classifier, a prediction of 1 would represent a very confident guess that the cookie is perfect and utterly mouthwatering. A prediction of 0 represents high confidence that the cookie is an embarrassment to the cookie industry. Values falling within this range represent less confidence, so we might design our system such that prediction of 0.6 means “Man, that’s a tough call, but I’m gonna go with yes, you can sell that cookie,” while a value exactly in the middle, at 0.5, might represent complete uncertainty. This isn’t always how confidence is distributed in a classifier but it’s a very common design and works for purposes of our illustration.

It turns out there’s a nice function that captures this behavior well. It’s called the sigmoid functiong(z), and it looks something like this:

h of x equals g of z The sigmoid function at work to accomplish a supervised machine learning example.

z is some representation of our inputs and coefficients, such as:

z equals theta 0 plus theta 1 times x

so that our predictor becomes:

h of x equals g of theta 0 plus theta 1 times x

Notice that the sigmoid function transforms our output into the range between 0 and 1.

The logic behind the design of the cost function is also different in classification. Again we ask “what does it mean for a guess to be wrong?” and this time a very good rule of thumb is that if the correct guess was 0 and we guessed 1, then we were completely and utterly wrong, and vice-versa. Since you can’t be more wrong than absolutely wrong, the penalty in this case is enormous. Alternatively if the correct guess was 0 and we guessed 0, our cost function should not add any cost for each time this happens. If the guess was right, but we weren’t completely confident (e.g. y = 1, but h(x) = 0.8), this should come with a small cost, and if our guess was wrong but we weren’t completely confident (e.g. y = 1 but h(x) = 0.3), this should come with some significant cost, but not as much as if we were completely wrong.

This behavior is captured by the log function, such that:

cost expressed as log

Again, the cost function J of theta gives us the average cost over all of our training examples.

So here we’ve described how the predictor h(x) and the cost function J of theta differ between regression and classification, but gradient descent still works fine.

A classification predictor can be visualized by drawing the boundary line; i.e., the barrier where the prediction changes from a “yes” (a prediction greater than 0.5) to a “no” (a prediction less than 0.5). With a well-designed system, our cookie data can generate a classification boundary that looks like this:

A graph of a completed machine learning example using the sigmoid function.

Now that’s a machine that knows a thing or two about cookies!

An Introduction to Neural Networks

No discussion of Machine Learning would be complete without at least mentioning neural networks. Not only do neural nets offer an extremely powerful tool to solve very tough problems, but they also offer fascinating hints at the workings of our own brains, and intriguing possibilities for one day creating truly intelligent machines.

Neural networks are well suited to machine learning models where the number of inputs is gigantic. The computational cost of handling such a problem is just too overwhelming for the types of systems we’ve discussed above. As it turns out, however, neural networks can be effectively tuned using techniques that are strikingly similar to gradient descent in principle.

A thorough discussion of neural networks is beyond the scope of this tutorial, but I recommend checking out our previous post on the subject.

Unsupervised Machine Learning

Unsupervised machine learning is typically tasked with finding relationships within data. There are no training examples used in this process. Instead, the system is given a set data and tasked with finding patterns and correlations therein. A good example is identifying close-knit groups of friends in social network data.

The Machine Learning algorithms used to do this are very different from those used for supervised learning, and the topic merits its own post. However, for something to chew on in the meantime, take a look at clustering algorithms such as k-means, and also look into dimensionality reduction systems such as principle component analysis. Our prior post on big data discusses a number of these topics in more detail as well.

This article is written by Nick McCrea and originally posted at Toptal

About the author: Nicholas is a professional software engineer with a passion for quality craftsmanship. He loves architecting and writing top-notch code, and is proud of his ability to synthesize and communicate ideas effectively to technical and non-technical folks alike. Nicholas always enjoys a novel challenge.

Reference

Have you ever found yourself going into the WordPress admin area to update themes, plugins, and WP core? Of course you have. Have you been asked, “Can you create/update/delete all the users on this CSV file?” I’m sure you’ve run into that too. Have you tried migrating a site and wished there were a plugin or third-party tool you could reach for to do the job? I know I have!

Automating Repetitive Tasks with WP-CLI

There is a very powerful tool available to help you with these tasks and more. Before I tell you about it, I would like to set up a quick anecdote.

The Problem: In a recent project, there were several programmatic tasks I needed to repeat on a regular basis. One task in particular involved updating user-level permissions based on evidence of membership-level purchase or subscription. If the company couldn’t find a payment from the user for a particular membership level, they wanted the membership level removed from the user. Why was this needed? Perhaps a member stopped a subscription, but an event did not fire, and so the member still has access even though they’re not paying for it (yikes!). Or perhaps someone was on a trial offer, but that offer expired and the client still has a subscription (also yikes!).

The Solution: Instead of going into the admin panel and manually deleting hundreds (maybe thousands) of subscriptions, I opted to reach for one of my favorite WordPress tools, WP-CLI, which fixed the problem in a few keystrokes.

In this post, I want to introduce you to WP-CLI (assuming you are not already close friends), walk you through a simple custom command I wrote for this particular situation, and give you some ideas and resources for using WP-CLI in your own development.

What Is WP-CLI?

If you have never heard of WP-CLI before, you’re not alone. The project, while several years old, seemed to fly under the WordPress radar for a while. Here’s a brief description of what WP-CLI is and does from the official website:

“WP-CLI is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite installs and much more, without using a web browser.”

The following commands show you the power of WP-CLI out of the box:

  • wp plugin update --all updates all updateable plugins.
  • wp db export exports a SQL dump of your database.
  • wp media regenerate regenerates thumbnails for attachments (e.g., after you change sizing in your theme).
  • wp checksum core verifies that WordPress core files have not been tampered with.
  • wp search-replace searches for and replaces strings in the database.

If you explore more commands here, you will see there are plenty of available commands for repetitive tasks every WordPress developer or site maintainer does on a daily or weekly basis. These commands have saved me countless hours of pointing, clicking, and waiting for page reloads over the course of the year.

Are you convinced? Ready to get started? Great!

You will need to have WP-CLI installed with your WordPress (or globally on your local machine). If you have not yet installed WP-CLI on your local development environment, installation instructions can be found on the website here. If you’re using Varying Vagrant Vagrants (VVV2), WP-CLI is included. Many hosting providers also have WP-CLI included on their platform. I will assume you have this successfully installed moving forward.

Using WP-CLI to Solve the Problem

To solve the problem of the repetitive tasks, we need to make a custom WP-CLI command available to our WordPress install. One of the easiest ways to add functionality to any site is to create a plugin. We will use a plugin in this instance for three main reasons:

  1. We will be able to turn off the custom command if we do not need it
  2. We can easily extend our commands and subcommands all while keeping things modular.
  3. We can maintain functionality across themes and even other WordPress installs.

Creating the Plugin

To create a plugin, we need to add a directory to our /plugins directory in our wp-content directory. We can call this directory toptal-wpcli. Then create two files in that directory:

  • index.php, which should only have one line of code: <?php // Silence is golden
  • plugin.php, which is where our code will go (You can name this file whatever you want.)

Open the plugin.php file and add the following code:

<?php
/**
 * Plugin Name: TOPTAL WP-CLI Commands
 * Version: 0.1
 * Plugin URI: https://n8finch.com/
 * Description: Some rando wp-cli commands to make life easier...
 * Author: Nate Finch
 * Author URI: https://n8finch.com/
 * Text Domain: toptal-wpcli
 * Domain Path: /languages/
 * License: GPL v3
 */
/**
 * NOTE: THIS PLUGIN FILE WILL NOT WORK IN PRODUCTION AS IS AND IS ONLY FOR DEMONSTRATION PURPOSES!
 * You can of course take the code and repurpose it:-).
 */
if ( !defined( 'WP_CLI' ) && WP_CLI ) {
    //Then we don't want to load the plugin
    return;
}

There are two parts to these first several lines.

First, we have the plugin header. This information is pulled into the WordPress Plugins admin page and allows us to register our plugin and activate it. Only the plugin name is required, but we should include the rest for anyone who might want to use this code (as well as our future selves!).

Second, we want to check that WP-CLI is defined. That is, we are checking to see if the WP-CLI constant is present. If it is not, we want to bail and not run the plugin. If it is present, we are clear to run the rest of our code.

In between these two sections, I’ve added a note that this code should not be used “as is” in production, since some of the functions are placeholders for real functions. If you change these placeholder functions to real, active functions, feel free to delete this note.

Adding the Custom Command

Next, we want to include the following code:

class TOPTAL_WP_CLI_COMMANDS extends WP_CLI_Command {

	function remove_user() {

		echo "\n\n hello world \n\n";

  	}

}

WP_CLI::add_command( 'toptal', 'TOPTAL_WP_CLI_COMMANDS' );

This block of code does two things for us:

  1. It defines the class TOPTAL_WP_CLI_COMMANDS, which we can pass arguments into.
  2. It assigns the command toptal to the class, so we can run it from the command line.

Now, if we execute wp toptal remove_user, we see:

$ wp toptal hello


 hello world

This means our command toptal is registered and our subcommand remove_user is working.

Setting Up Variables

Since we are bulk processing removing users, we want to set up the following variables:

// Keep a tally of warnings and loops
  $total_warnings = 0;
  $total_users_removed = 0;

// If it's a dry run, add this to the end of the success message
  $dry_suffix = '';

// Keep a list of emails for users we may want to double check
  $emails_not_existing = array();
  $emails_without_level = array();

// Get the args
  $dry_run = $assoc_args['dry-run'];
  $level = $assoc_args['level'];
  $emails = explode( ',', $assoc_args['email'] );

The intent of each of the variables is as follows:

  • total_warnings: We will tally a warning if the email does not exist, or if the email is not associated with the membership level we are removing.
  • $total_users_removed: We want to tally the number of users removed in the process (see caveat below).
  • $dry_suffix: If this is a dry run, we want to add wording to the final success notice.
  • $emails_not_existing: Stores a list of emails that do not exist.
  • $emails_without_level: Stores a list of emails that do not have the specified level.
  • $dry_run: A boolean that stores whether the script is doing a dry run (true) or not (false).
  • $level: An integer representing the level to check and possibly remove.
  • $email: An array of emails to check against the given level. We will loop through this array

With our variables set, we are ready to actually run the function. In true WordPress fashion, we will run a loop.

Writing the Function Itself

We start by creating a foreach loop to cycle through all the emails in our $emails array:

// Loop through emails
foreach ( $emails as $email ) {

	// code coming soon

} // end foreach

Then, we add a conditional check:

// Loop through emails
foreach ( $emails as $email ) {
	//Get User ID
	$user_id = email_exists($email);

	if( !$user_id ) {

		WP_CLI::warning( "The user {$email} does not seem to exist." );

		array_push( $emails_not_existing, $email );

		$total_warnings++;

		continue;
	}
} // end foreach

This check ensures we have a registered user with the email we are checking. It uses the email_exists()function to check if there is a user with that email. If it does not find a user with that email, it throws a warning so that we know on our terminal screen that the email was not found:

$ wp toptal remove_user --email=me@me.com --dry-run

Warning: The user me@me.com does not seem to exist.

The email is then stored in the $emails_not_existing array for display later. Then we increment the total warning by one and continue through the loop to the next email.

If the email does exist, we will use the $user_id and the $level variables to check if the user has access to the level. We store the resulting boolean value in the $has_level variable:

// Loop through emails
foreach ( $emails as $email ) {
	//Get User ID
	$user_id = email_exists($email);

	if( !$user_id ) {

		WP_CLI::warning( "The user {$email} does not seem to exist." );

		array_push( $emails_not_existing, $email );

		$total_warnings++;

		continue;
	}

	// Check membership level. This is a made up function, but you could write one or your membership plugin probably has one.
	$has_level = function_to_check_membership_level( $level, $user_id );

} // end foreach

Like most functions in this example, this function_to_check_membership_level() function is fabricated, but most membership plugins should have helper functions to get you this information.

Now, we’ll move on to the main action: removing the level from the user. We will use an if/else structure, which looks like this:


foreach ( $emails as $email ) {

	// Previous code here...


	// Check membership level. This is a made up function, but you could write one or your membership plugin probably has one.
	$has_level = function_to_check_membership_level( $level, $user_id );

	if ( $has_level ) {

		if ( !$dry_run ) {

		// Deactivate membership level. This is a made up function, but you could write one or your membership plugin probably has one.
			function_to_deactivate_membership_level( $level, $user_id, 'inactive' );

		}

		WP_CLI::success( "Membership canceled for {$email}, Level {$level} removed" . PHP_EOL );

		$total_users_removed++;

	} else {

		WP_CLI::warning( "The user {$email} does not have Level = {$level} membership." );

		array_push( $emails_without_level, $email );

		$total_warnings++;
	}

	// We could echo something here to show that things are processing...

} // end foreach

If the value of $has_level is “truthy,” meaning the user has access to the membership level, we want to run a function to remove that level. In this example, we will use the function_to_deactivate_membership_level()function to perform this action.

However, before we actually remove the level from the user, we want to enclose that function in a conditional check to see if this is actually a dry-run. If it is, we do not want to remove anything, only report that we did. If it is not a dry-run, then we will go ahead and remove the level from the user, log our success message to the terminal, and continue looping through the emails.

If, on the other hand, the value of $has_level is “falsey,” meaning the user does not have access to the membership level, we want to log a warning to the terminal, push the email to the $emails_without_levelarray, and continue looping through the emails.

Finishing Up and Reporting

Once the loop has finished, we want to log our results to the console. If this was a dry run, we want to log an extra message to the console:

if ( $dry_run ) {
	$dry_suffix = 'BUT, nothing really changed because this was a dry run:-).';
}

This $dry-suffix will be appended to the warnings and success notifications that we log next.

Finishing up, we want to log our results as a success message and our warnings as warning messages. We will do so like this:

WP_CLI::success( "{$total_users_removed} User/s been removed, with {$total_warnings} warnings. {$dry_suffix}" );

if ( $total_warnings ) {

	$emails_not_existing = implode(',', $emails_not_existing);
	$emails_without_level = implode(',', $emails_without_level);

	WP_CLI::warning(

		"These are the emails to double check and make sure things are on the up and up:" . PHP_EOL .
		"Non-existent emails: " . $emails_not_existing . PHP_EOL .
		"Emails without the associated level: " . $emails_without_level . PHP_EOL

	);
}

Note that we are using the WP_CLI::success and WP_CLI::warning helper methods. These are provided by WP-CLI for logging information to the console. You can easily log strings, which is what we do here, including our $total_users_removed$total_warnings, and $dry_suffix variables.

Finally, if we did accrue any warnings throughout the runtime of the script, we want to print that information to the console. After running a conditional check, we convert the $emails_not_existing and $emails_without_level array variables into string variables. We do this so we can print them to the console using the WP_CLI::warning helper method.

Adding a Description

We all know comments are helpful to others and to our future selves going back to our code weeks, months, or even years later. WP-CLI provides an interface of short descriptions (shortdesc) and long descriptions (longdesc) which allows us to annotate our command. We will put at the top of our command, after the TOPTAL_WP_CLI_COMMANDS class is defined:


/**
 * Remove a membership level from a user
 *
 * ## OPTIONS
 * --level=<number>
 * : Membership level to check for and remove
 *
 * --email=<email>
 * : Email of user to check against
 *
 * [--dry-run]
 * : Run the entire search/replace operation and show report, but don't save changes to the database.
 *
 * ## EXAMPLES
 *
 * wp toptal remove_user --level=5 --email=me@test.com,another@email.com, and@another.com --dry-run
 *
 * @when after_wp_load
 */

In the longdesc, we define what we expect our custom command to receive. The syntax for the shortdesc and longdesc is Markdown Extra. Under the ## OPTIONS section, we define the arguments we expect to receive. If an argument is required, we wrap it in < >, and if it is optional, we wrap it in [ ].

These options are validated when the command is run; for example, if we leave out the required email parameter, we get the following error:

$ wp toptal remove_user --level=5 --dry-run
Error: Parameter errors:
 missing --email parameter (Email of user to check against)

The ## EXAMPLES section includes an example of what the command could look like when being called.

Our custom command is now complete. You can see the final gist here.

A Caveat and Room for Improvement

It is important to review the work that we have done here to see how the code could be improved, expanded and refactored. There are many areas of improvement for this script. Here are some observations about improvements that could be made.

Occasionally, I have found this script will not remove all the users it logs as “removed.” This is most likely due to the script running faster than the queries can execute. Your experience may vary, depending on the environment and setup in which the script is run. The quick way around this is to repeatedly run with the same inputs; it will eventually zero out and report that no users have been removed.

The script could be improved to wait and validate that a user has been removed before logging the user as actually removed. This would slow down the execution of the script, but it would be more accurate, and you would only have to run it once.

Similarly, if there were errors found like this, the script could throw errors to alert that a level had not been removed from a user.

Another area to improve the script is to allow for multiple levels at a time to be removed from one email address. The script could auto-detect if there were one or more levels and one or more emails to remove. I was given CSV files by level, so I only needed to run one level at a time.

We could also refactor some of the code to use ternary operators instead of the more verbose conditional checks we currently have. I have opted to make this easier to read for the sake of demonstration, but feel free to make the code your own.

In the final step, instead of printing emails to the console in the final step, we could also automatically export them to a CSV or plain text file

Finally, there are no checks to make sure we’re getting an integer for the $level variable or an email or comma-separated list of emails in the $emails variable. Currently, if someone were to include strings instead of integers, or user login names instead of emails, the script would not function (and throw no errors). Checks for integers and emails could be added.

Ideas for Further Automation and Further Reading

As you can see, even in this specific use case, WP-CLI is quite flexible and powerful enough to help you get your work done quickly and efficiently. You may be wondering to yourself, “How can I begin to implement WP-CLI in my daily and weekly development flow?”

There are several ways you can use WP-CLI. Here are some of my favorites:

  • Update themes, plugins, and WP core without having to go into the admin panel.
  • Export databases for backup or perform a quick SQL dump if I want to test a SQL query.
  • Migrate WordPress sites.
  • Install new WordPress sites with dummy data or custom plugin suite setups.
  • Run checksums on core files to make sure they have not been compromised. (There is actually a project underway to expand this to themes and plugins in the WP repo.)
  • Write your own script to check, update, and maintain site hosts (which I wrote about here).

The possibilities with WP-CLI are just about limitless. Here are some resources to keep you moving forward:

This article is written by Nathan Finch and originally published at Toptal

About the Author:  Nathan works primarily in WordPress front-end development—consulting and implementing with Genesis and WooCommerce for SME businesses and enterprise level projects. He uses WordPress, HTML, CSS, PHP, and JavaScript on a daily basis as well as Sass, Git, jQuery, and Grunt. Nathan is constantly exploring and experimenting with other front-end technologies and frameworks like Angular and React.

 

Salesforce Einstein. The AI revolution is already transforming the consumer world.

Sometimes, it’s in everyday ways like product recommendations, and sometimes it’s in magnificent ways: Cochlear implants, which provide artificial hearing for those born completely deaf, have switched to AI for a superior end-user experience.

Artificial intelligence (AI) is the latest milestone in modern technology.

The AI revolution is leading to a smarter world, and this smarter world has been built on the mega-trends that we’ve all witnessed over the last 20 years: the web, the cloud, social, mobile, and the Internet of Things (IoT).

With cloud technology, we have, as developers, virtually unlimited computing and storage capacity, and it’s really that combination of massive data and massive computing power that’s leading to this revolution. Now that everybody is connected to each other and to everything in some way or another, all of these connections are generating orders of magnitude more data for the AI cloud to process than ever before.

You experience the AI cloud every day as a consumer. When you see a product recommendation on Amazon, a movie recommendation on Netflix, or a photo that’s automatically identified and tagged in your Facebook feed, you’re experiencing the power of AI.

Now wouldn’t it be great if the app you’re working on—whether it’s a Salesforce app or not—could somehow also provide these smarter, AI-powered experiences? For example, what if our business and our sales app could work together to tell us which leads are most likely to convert, or our service app could use the AI cloud to tell us which cases are likely to be escalated?

Unfortunately, for many teams, it seems too complex and expensive to apply AI to their app’s business process. First, it starts with data science and, to do data science, you have to collect and integrate all the required data. And then you need to do data wrangling, transforming the data so that you can use it for machine learning. And then, depending on your expertise, you may even need outside help from data scientists to build predictive models, maintain them, refresh them, and create an infrastructure that is trusted and secure and scalable. Then, after all that work, you have to take these predictions and put them into the context of the business user.

Enter Salesforce Einstein

Knowing that AI was often out of reach, Salesforce acquired companies like MetaMind (deep learning specialists), Implisit Insights (applying AI to the sales process specifically), and PredictionIO (machine learning and big data analytics) to help them build Salesforce Einstein.

Salesforce Einstein is AI for Salesforce, and it’s built right into the platform. As Einstein’s GM put it, “It takes the world’s number one CRM and makes it the world’s smartest CRM.” With Salesforce’s AI offering, you can now empower a company’s sales, service, marketing, and IT professionals to be their best by making every customer interaction faster, smarter, and more predictive.

Deep Learning: Einstein Vision and Einstein Language

Salesforce Einstein should bring the AI cloud within reach of developers. Maybe. But where should you start? The first thing to know is that AI has three major components:

  • Data
  • Algorithms
  • Computation

Big data in general has been a hot topic for the past couple of years. Everyone is excited to have new sources of data, new ways of analyzing it, and new ways of storing it.

This is going to be a big part of how we bring artificial intelligence into the enterprise but a lot of the AI development effort has been on the algorithm side. These are complex algorithms that are being built upon, expanded, and actually having new research from both the private and public sectors. You can be sure that AI cloud algorithms are going to continue to be innovative and continue to drive new features for your applications and for customer experiences.

The computation aspect you’ve probably heard of lately, too: GPUs, TPUs, new investments, and new research from all the best hardware companies are all going towards computing power, ensuring that these algorithms have the infrastructure they need to continue to be innovative and to be able to provide insight into your data.

Before we get into how you can develop something that leverages this technology, let’s dig into some more details of what you’ll be dealing with.

The Data

There are two forms of data to consider here: Structured and unstructured.

Structured and unstructured data.

Structured data includes your ERP data and the majority of your CRM data; it could be data coming out of IoT devices, for example. This type of data is already easily searchable by basic algorithms.

Unstructured data could be your image data, email messages, PowerPoint presentations, Word documents, etc. This is where deep learning and machine learning algorithms come in, vastly simplifying how we search through this type of data.

The Algorithm

Deep learning is a complicated term: A lot of developers and DevOps engineers get overwhelmed by it. They think they don’t have the infrastructure to handle neural networks. They think they need a PhD to sufficiently understand the state-of-the-art model to be incorporated in order to break it down into a more manageable thought process. Fortunately, knowing enough of it to be able to leverage it is a lot more accessible than that.

You only need to know about the input and output layers; all the really difficult work happens in the hidden layer, which is taken care of by the Salesforce AI cloud.

Let’s start this way: You have an input file. This could be an image, an audio file, or a text file. And you want to derive insightful output from it. Salesforce Einstein has a set of APIs which you can use to make this process really seamless: You don’t have to know anything about what happens in between.

With Salesforce Einstein, it is very easy for you to embed deep learning into your applications. It provides you with well-hosted infrastructure that manages your models as a service and thus takes care of any scalability needs. So it makes it easy for you to upload, train, and understand your model metrics, and in the end provide predictions in real time on a pre-trained model or a custom model that you create.

If even that sounds foreign to you, the next examples will quickly get you up to speed.

Computation: Einstein Vision

This is one of the deep learning services offered by Salesforce Einstein. Not all deep learning models or neural networks are equal: Specific architectures are used for specific problems. And in the case of computer vision, the AI cloud uses what is called a convolutional neural network, which means that each layer learns from the previous one. So when such a network is trained on image data, it rebuilds the image from the ground up to understand its different components. It will first look at an image’s smallest unit, the pixel, and then understand the edges, and then the next layer understands object parts or elements, and then eventually it gets to whole objects.

And that entire process is taken care of for you, so you can focus on the business value you can unlock for your clients with computer vision instead of on the process itself.

Einstein Vision can be trained to recognize objects in images.

Think about how the transportation industry could be transformed by using drones to monitor highways—no one would need to send a cleanup crew.

Or how CPG companies, instead of sending individuals to manually record the products on a shelf, could just take a picture and have it be automatically analyzed.

Or how consumer retail can be revolutionized with visual search, or how insurance companies can automate the triaging of claims, or how image processing can be leveraged by healthcare.

All such scenarios can be covered by Einstein Image Classification, which is part of Einstein Vision. All you need is a model, which is more or less just a set of classification labels.

Build a Custom Model

A custom model can predict the classification of new data based on a training dataset made of data with known classifications.

You can build your own custom models and then integrate these within your workflows, whether that’s a Salesforce workflow or an external application.

Building your own custom model involves just three steps:

  1. Create your own data set, based on what your custom model needs to do. Say you want to be able to tell the difference between three-door refrigerators and two-door refrigerators. You’ll need to collect a bunch of images of two-door refrigerators and put them in a folder, and then a bunch of images of three-door refrigerators and put them in another folder.
  2. Train your model. Now, whatever data sets you collected in the previous step, you upload them and the AI cloud will train the model based on that dataset. The fact that you already separated the images is all that’s needed for training. Once the new data model is trained, you will receive its ID.
  3. Use it for prediction! You can now get predictions on images that the model has never seen before. It’s as simple as making an API call using the new model ID.

Computation: Einstein Language

If images aren’t what you need to process, chances are you’re looking to train using text. For this, Salesforce’s AI cloud has Einstein Language, which is currently made of two services: Einstein Intent and Einstein Sentiment.

  • Einstein Intent is a general classifier of the natural language processing (NLP) type. It allows you to define your own classes and upload data that represents those classes.
  • Einstein Sentiment is a pre-trained model which is able to analyze human language to derive the feelings of the content and surrounding users’ statements and classify those into positive, negative, and neutral classes.
Einstein Language's model makes natural-language AI cloud training and classification easily accessible to your Salesforce Einstein app via an API.

Einstein Language services work just like our image classification example. Here, we will also define classes.

In the above example, the intent is about routing cases. Every time a case comes through, we want to analyze that and route it to the right department: Shipping, billing, product, sales…we can define as many classes as we need. But in the case of Einstein Sentiment, the classes are fixed, so we just have positive, negative, or neutral.

Once you have separated the data into different classes, you can train your models. Training the model is very easy with the provided API. Just like with Einstein Vision, once the model is trained, you’ll have your model ID and you’re ready to get predictions.

Salesforce Einstein: Off to a Smart Start

Now that you have a taste for the possibilities that Salesforce Einstein brings within your reach as a Salesforce developer, and how easy it would be to help your clients or employer leverage the AI cloud, getting started merely requires setting up an account. We look forward to hearing how you’re using the AI cloud to revolutionize your own app!

This article written by Fahad Munawar Khan and is originally posted at Toptal

 

About the Author:

Fahad is a Salesforce Certified Force.com developer with 5 years of experience working on various client engagements in the web technology area. He takes pride in creating solutions that not only satisfies the requirements, but also makes the best possible usage of all Salesforce platform features and resources.

Here are the top 15 places to find an AngularJS developer:

1. Toptal

Toptal is a matching service, initially created with only tech talent in mind. Although it has expanded its pool of talent to include designers and finance experts, the company’s bread and butter is its developer vertical. If you want to be sure that an AngularJS developer is up to the job, hiring an exceptional developer from Toptal is likely your best option.

Why? Toptal boasts an elite developer base. Their trademark system for vetting talent allows for only the best to become a part of their community. According to Toptal, only 3% of applicants make it through their battery of technical tests and their comprehensive vetting process.

2. Hired

Hired helps employers find software engineers and developers. On Hired, you can use their pipeline to find custom matches. You can create a company profile, search for candidates using their search algorithm (which can eliminate gender and racial identifiers for fairer hiring), and request interviews with candidates.

What’s best about Hired? It’s great for finding specialized AngularJS developers who are actively searching for new opportunities, have relevant experience (as most candidates on Hired have at least two years of experience), and are in your area.

3. GitHub Jobs

Don’t waste your time perusing large job boards like Monster and Indeed. You’ll have far better luck with job boards geared toward tech talent. GitHub has a massive developer community as it’s one of the largest open-source online repositories for coders. For a relatively small fee, you can post an AngularJS developer job listing and gain a great deal of exposure on GitHub’s huge developer community.

4. Angular Jobs

While Job boards like GitHub can be enormously helpful, smaller job boards that focus solely on placing Angular developers with businesses can be an incredible resource as well. Angular Jobs is one such resource.

First and foremost, Angular Jobs is a community. The owners of the popular Angular job board are very serious about providing gainful employment to developers and fostering a community founded on mutual benefit and respect. “We exist to create synergy,” states Brian Petro, founder of Angular Jobs, “between developers and employers.” The feeling of community is fostered by the curation of Angular content, JavaScript learning tools as well as Angular news.

5. Stack Overflow

Stack Overflow has an online community that rivals GitHub. Arguably, it’s the absolute largest and most trusted community of developers on the web. Stack Overflow is often used as a resource for all kinds of developers, novice to expert, seeking to learn more about coding. Their job board, like GitHub’s, allows for an incredible amount of exposure to dedicated AngularJS developersaround the world.

6. Upwork

If recruiting services and job boards aren’t your thing, you might want to consider a freelance marketplace like Upwork.

Upwork has one of the largest marketplaces with millions of registered freelancers. You can hire contractors for a few simple coding tasks or begin a long-term relationship with a series of complex AngularJS projects. If you like the idea of finding, interviewing, and managing freelancers, Upwork’s colossal marketplace will likely meet your needs.

7. People Per Hour

People Per Hour is another freelance marketplace akin to Upwork. What makes People Per Hour unique is that it holds contests and allows Freelancers to post their own job postings called hourlies.

People Per Hour has millions of members, thousands of confirmed hours, and a plethora of success stories from freelancers and entrepreneurs alike. The ease of posting jobs, contacting freelancers, and paying for hours worked makes People Per Hour a superb choice for employers interested in searching for and vetting freelance candidates themselves.

Additionally, with People Per Hour, you can connect with local freelancers, so you aren’t necessarily limited to remote talent.

8. Gun.io

Gun.io has a growing community of developers over 25,000 strong. Like Toptal, their service is designed to take the tedium out of hiring. Gun.io vets their talent and ensures that their freelancers are committed to each and every project.

Gun.io prides itself on its humanism. Every employer is connected with a VP, instead of a sales representative, and freelancers are provided with the resources to succeed.

What’s most alluring about the network? Gun.io manages and replaces talent – with no risk to you – and back every single hour worked with a 100% money-back guarantee.

9. Guru

Guru has a large global network of freelancers—albeit smaller than Upwork’s and People Per Hour’s massive pool. You can explore the profiles of 1.5 million gurus, propose projects, and pay your hired talent with their secure SafePay system.

Guru isn’t focused on developers, let alone Angular developers, as it is a freelance network comprised of every sort of professional. So, like with Upwork and People Per Hour, you’ll have to narrow your search yourself. Also, as with many freelance networks, the vetting and interviewing will be up to you.

10. We Love Angular

We Love Angular pulls Angular job postings from all over the world. It also has sections completely dedicated to available AngularJS developers. Developers simply tweet @weloveangular with the hashtag #AngularJS, as well as other hashtags related to their expertise, and a link to an updated resume.

Employers can post jobs on We Love Angular with ease. In fact—posting a job is completely free. The entire job board is dedicated solely to AngularJS, so you’ll be able to get in touch with JavaScript developers quite easily at zero cost to you.

Unfortunately, the open nature of We Love Angular is also a great weakness. There’s no vetting process in place. This means everything that goes through We Love Angular is unfiltered.

11. Freelancer

Freelancer is an absolutely massive marketplace with 25 million registered users, 12 million total posted jobs, and thousands of completed projects. With the size of the marketplace comes a unique challenge, however. Finding the perfect AngularJS developer is like finding a needle in a haystack.

Although website development is one of the most popular job categories on Freelancer, you still will have to search through thousands of Freelancer profiles, vet and interview candidates yourself, and manage payments yourself.

If you’re looking for an affordable option, however, Freelancer is a wonderful hiring solution. For more long-term commitments, you’ll want to consider matching services like Toptal, Gun.io, or even Hired.

12. Find Bacon

Find Bacon is a job board aimed at eliminating the hassle of searching for design and development jobs. Find Bacon is a pleasant alternative to massive job boards like Indeed and Monster and is highly affordable. Posting a job posting for a 30-day period is only $99 dollars.

They also offer subscription packs which allow for 10 job posts a month. If you’re a company looking to fill multiple positions or are planning on hiring freelancers on an ongoing basis, you may want to consider investing in a subscription pack for a niche job board like Find Bacon.

13. AngularJobs.io

Another job board catering only to AngularJS job listings, AngularJobs.io is a fabulous place to search for the right AngularJS developers.

AngularJobs.io would have received the honor of a higher listing, but, considering it’s a fairly new site and requires a user account to navigate, it’s not the optimal website to begin your search for talented AngularJS developers.

14. X-Team

X-Team matches you with highly-qualified, unbelievably-motivated developers who receive mentorship and educational resources just for being a part of X-Team. Like Toptal and Gun.io, they do the heavy lifting of hiring. You won’t be saddled with rifling through resumes or preparing personalized interview scripts.

The major downside of using X-Team is that, as their name suggests, they are adept at organizing teams. If you’re only looking to hire an individual AngularJS developer, you’ll want to use a different matching service.

15. College Recruiter

If you’re looking to fill a part-time, entry-level position, or internship, College Recruiter is a good place to connect with college students and recent grads. This is an especially good option if you happen to constrained to a tight budget and have flexibility in terms of a hiring schedule.

Again, you’ll have to do the hard work of vetting and interviewing, but if interviewing hires doesn’t sound too daunting, College Recruiter is a good place to search for entry-level talent.

Honorable Mention: SimplyHired

SimplyHired is a large job board. It’s similar to big, general job boards like Indeed or Monster. The site comes with loads of resources from salary recommendations to hiring guides, and offers low prices for job listings. Like with Indeed and Monster, you’ll get a great deal of exposure. With over a billion job applications delivered, SimplyHired is a highly-respected job board worth investigating.

Begin exploring salary estimators, post within a network of over a hundred job boards in record time, and browse through the collated jobs by cities to see if posting a job listing on SimplyHired is worth the time and money for you.

Choosing the right site

Finding the best sites to find developers is no easy endeavor. Unless you’re a battle-worn recruiter, you likely won’t know how to navigate the complexities of hiring an AngularJS developer. That’s completely okay—there’s plenty of sites and services to help you along the way.

Matching services like Toptal, and to a lesser extent, Hired and Gun.io, are great solutions for employers searching for tech talent, and for those who are looking to place their trust in experienced recruiters. For those short on time with high-quality developers as a priority, Toptal and Gun.io are superb choices.

On the other end of the spectrum, there are freelance marketplaces like Upwork, People Per Hour, and Freelancer that allow you to cast a much wider net for AngularJS developers. Employers looking for full-time developers may also benefit from utilizing Stack Overflow and GitHub’s job boards, which can provide wonderful exposure to the AngularJS developer community. Specialized job boards with cohesive online communities like We Love Angular and AngularJobs.io can also be immensely helpful in your search for qualified developers.

Freelance marketplaces like Upwork, Freelancer, and Guru allow you to instantly connect with developers, but you’ll have to care for the hiring details yourself. If you have ample time to devote to screening candidates and are confident in your ability to interview AngularJS developers, they are a great choice. Otherwise, you should steer clear from marketplaces and job boards alike.

Job boards, marketplaces, and matching services all have their uses. Which site will best serve you will depend on your specific situation.

Ultimately, which sites you employ depends on a multitude of factors, such as:

  • How quickly you need to hire a freelancer (i.e. your timeline)
  • How much experience you have hiring AngularJS developers
  • Whether or not you’re equipped to test technical skills
  • How many developers you need to bring on
  • What level of experience those AngularJS freelancers need
  • Whether or not you’re open to remote workers
  • What your budget constraints are
  • How important quality is to your project(s)

Source: DevelopersForHire.com