Bind a Service to Your App

Page last updated:

Page last updated:

The service marketplace has a large number of data stores, from Redis and MongoDB, to MariaDB (fork of MySQL) and RabbitMQ. You can run cf marketplace to get an overview. In this step you will add a small MariaDB database to your app.

Create the database:

$ cf create-service mariadb small my-mariadb
Creating service instance my-mariadb in org MyOrg / space MySpace as user@mydomain.com...
OK

Create in progress. Use 'cf services' or 'cf service my-mariadb' to check operation status.

Attention: The plan `small` of service `mariadb` is not free.  The instance `my-mariadb` will incur a cost.  Contact your administrator if you think this is in error.

This creates a small MariaDB database for you which we now have to bind to our application. Binding means that the credentials and URL of the service will be written dynamically into the environment variables of the app as VCAP_SERVICES and can hence be used directly from there.

Let’s bind the new service to our existing application:

$ cf bind-service my-php-app my-mariadb
Binding service my-mariadb to app my-php-app in org MyOrg / space MySpace as user@mydomain.com...
OK
TIP: Use 'cf restage my-php-app' to ensure your env variable changes take effect

After that we restage the application as suggested so that it includes the new credentials in its environment variables:

$ cf restage my-php-app
Restaging app my-app in org MyOrg / space MySpace as user@mydomain.com...
-----> Downloaded app package (8.0K)
-----> Creating runtime environment

...

Now we want to consume our new MariaDB from within our application. Lucky you! Laravel Lumen already comes with everything you need to handle your database.

Your MariaDB’s connection credentials are all stored in the environment variable VCAP_SERVICES.

You also have to pass the MariaDB connection credentials to Laravel Lumen in the file config/database.php. Add the following code right before the return statement:

$cfEnv = $_ENV['VCAP_SERVICES'];
if (isset($cfEnv)) {
  try {
    $vcapServices = json_decode($_ENV['VCAP_SERVICES']);
    $mariaDbConnection = head($vcapServices->mariadb)->credentials;

    putenv('DB_CONNECTION=mysql');
    putenv('DB_HOST=' . $mariaDbConnection->host);
    putenv('DB_PORT=' . $mariaDbConnection->port);
    putenv('DB_DATABASE=' . $mariaDbConnection->database);
    putenv('DB_USERNAME=' . $mariaDbConnection->username);
    putenv('DB_PASSWORD=' . $mariaDbConnection->password);
    putenv('APP_ENV=production');
    putenv('APP_DEBUG=false');
    putenv('APP_KEY=CFENV!!!');
  }
  catch (Exception $e) {
    dd($e->getMessage());
  }
}

This checks if the app is running in the cloud. If not, it falls back to to use the values in .env. This allows you to run your app locally as well as in the cloud without having to configure anything differently.

Now we need to apply some changes to app/Http/routes.php.

Add the following code to have a route which triggers a DB migration task:

$app->get('/migrate', function () {
  try {
    \Illuminate\Support\Facades\Artisan::call('migrate', ['--force' => true]);
    return response()->json(['migrated' => true]);
  } catch (Exception $e) {
    return response()->json([
      'error' => $e->getMessage(),
      'trace' => $e->getTrace()
    ]);
  }
});

This migration task takes all migration files from database/migrations/* and executes the SQL code so we have some tables in our MariaDB.

Next we add some routes to app/Http/routes.php to make actual changes on the database:

$app->get('/users/add/{amount}', function ($amount) {
  $faker = Faker\Factory::create();
  $users = [];

  for ($i = 0; $i < $amount; $i++) {
    array_push($users, [
      'firstName' => $faker->firstName,
      'lastName' => $faker->lastName,
      'birthday' => $faker->date(),
      'email' => $i . $faker->email,
      'password' => $faker->password
    ]);
  }
  try {
    \Illuminate\Support\Facades\DB::table('users')->insert($users);
    return response()->json([
      'amount' => $amount,
      'users added' => $users
    ]);
  } catch (Exception $e) {
    return response()->json(
      [
        'error' => $e->getMessage(),
        'trace' => $e->getTrace()
      ]
    );
  }
});

$app->get('/users', function () {
  $result = \Illuminate\Support\Facades\DB::table('users')->get();
  $count = \Illuminate\Support\Facades\DB::table('users')->count();
  return response()->json([
    'count' => $count,
    'users' => $result
  ]);
});

$app->get('/users/delete', function () {
  \Illuminate\Support\Facades\DB::table('users')->truncate();
  $result = \Illuminate\Support\Facades\DB::table('users')->get();
  return response()->json(['users' => $result]);
});

Your app can now do the following things:

  1. Add a costum amount of users to the database on GET /users/add/{amount}
  2. Read all users on GET /users
  3. Delete all users on GET /users/delete

Note: These are all implemented as GET requests so you can hit them easily from your browser. In production you should use different HTTP methods for these calls.

Now let’s push all these changes to the cloud using

$ cf push my-php-app

You can access other services like Redis or MongoDB in a similar matter, simply by binding them to your app and accessing them through the environment variables.

Important: You have to hit the /migrate endpoint once to perform a database migration before you can use the /users endpoints.

I’ve bound a service to my App
View the source for this page in GitHub