Skip to content

PHPLIB-1163 Create tutorial for using MongoDB with Bref #1273

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ psalm.xml
.phpbench/
phpbench.json

# bref
.serverless/

mongocryptd.pid
19 changes: 19 additions & 0 deletions docs/examples/aws-lambda/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "mongodb/bref-tutorial",
"type": "project",
"license": "MIT",
"repositories": [
{
"type": "path",
"url": "../../..",
"options": {
"symlink": false
}
}
],
"require": {
"bref/bref": "^2.1",
"bref/extra-php-extensions": "^1.4",
"mongodb/mongodb": "@dev"
}
}
28 changes: 28 additions & 0 deletions docs/examples/aws-lambda/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

use MongoDB\Client;

require_once __DIR__ . '/vendor/autoload.php';

$uri = getenv('MONGODB_URI') ?: throw new RuntimeException('The MONGODB_URI environment variable is not set');
$client = new Client($uri);
$planets = $client->sample_guides->planets
->find(
[],
['sort' => ['orderFromSun' => 1]],
);

?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>MongoDB Planets</title>
</head>
<body>
<ul>
<?php foreach ($planets as $planet) : ?>
<li><?= $planet->name ?></li>
<?php endforeach ?>
</ul>
</body>
</html>
22 changes: 22 additions & 0 deletions docs/examples/aws-lambda/serverless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
service: app

provider:
name: aws
region: us-east-1
environment:
MONGODB_URI: ${env:MONGODB_URI}

plugins:
- ./vendor/bref/bref
- ./vendor/bref/extra-php-extensions

functions:
api:
handler: index.php
description: ''
runtime: php-83-fpm
timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
events:
- httpApi: '*'
layers:
- ${bref-extra:mongodb-php-83}
1 change: 1 addition & 0 deletions docs/tutorial.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ Tutorials
/tutorial/indexes
/tutorial/tailable-cursor
/tutorial/example-data
/tutorial/aws-lambda
/tutorial/modeling-bson-data
/tutorial/stable-api
124 changes: 124 additions & 0 deletions docs/tutorial/aws-lambda.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
==============================
Deploy to AWS Lambda with Bref
==============================

.. default-domain:: mongodb

.. contents:: On this page
:local:
:backlinks: none
:depth: 2
:class: singlecol

.. versionadded:: 1.17

Overview
--------

`Bref <https://bref.sh>`_ allows to deploy serverless PHP applications on AWS Lambda.
In this tutorial, you will deploy a simple PHP application with the MongoDB PHP extension,
and connect to an Atlas cluster using AWS IAM authentication.

Prerequisites
--------------

Before you begin, you must install Bref on your machine. You can follow the
`official documentation to setup Bref <https://bref.sh/docs/setup>`_.

Install the MongoDB extension
-----------------------------

By default, the bref layer is compiled with PHP and a few extensions. Additional extensions
are provided in additional layers.

Start by creating a new directory for your project and install the required MongoDB
and Bref dependencies. This project will be a bare minimum PHP web application that
connects to a MongoDB cluster.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion:

I think this task was already described in more detail in the first section, so this sentence should be omitted to avoid repetition and clutter.

Suggested change
and Bref dependencies. This project will be a bare minimum PHP web application that
connects to a MongoDB cluster.
and Bref dependencies by running the following commands:


.. code-block:: bash

mkdir bref-mongodb-app && cd bref-mongodb-app
composer init
composer require bref/bref bref/extra-php-extensions mongodb/mongodb
vendor/bin/bref init


The file ``index.php`` has been created. To validate the deployment, you can start
by deploying this default application.

.. code-block:: bash

serverless deploy


Bref provides a Lambda layer with PHP and some very common extensions.
Additional extensions are provided by the package `bref/extra-php-extension <https://github.com/brefphp/extra-php-extensions>`_.

.. code-block:: yaml

plugins:
- ./vendor/bref/bref
- ./vendor/bref/extra-php-extensions

functions:
api:
handler: index.php
runtime: php-83-fpm
layers:
- ${bref-extra:mongodb-php-83}


Let's try to use the MongoDB driver with this simple web page that list planets
from the :manual:`sample dataset </atlas/sample-data/>`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ccho-mongodb: Is this the correct prefix?

The intended URL is https://www.mongodb.com/docs/atlas/sample-data/, but conf.py in mongodb/docs-php-library suggests this will be "http://docs.mongodb.org/manual%s".

Now that I'm thinking about it, that pattern looks incorrect since all docs should be pointing to a mongodb.com domain. There's also the omission of "https".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I got it wrong. The prefix should be added. Maybe added to this standing PR: mongodb/docs-php-library#57

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted to full url links for the time being.

Copy link

@ccho-mongodb ccho-mongodb Apr 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the extlinks entry may override the Snooty role. The Docs Platform team can probably confirm/deny this.

For example, docs-java doesn't have a conf.py file and therefore no extlinks, but uses the :manual: role:
https://github.com/mongodb/docs-java/blob/612975d4e0a2b550a9eb486b75558afb6ee7c55b/source/usage-examples/watch.txt#L181-L183

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I asked about this in Slack and will revise mongodb/docs-php-library#57 based on the response.

Replace the contents of ``index.php`` with the following:

.. literalinclude:: /examples/aws-lambda/index.php
:language: php


Deploy the application

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue:
This seems to be missing punctuation.
If this is meant to be the title of a step, maybe this tutorial can be formatted as steps.
Here's an example:

Kafka tutorial
RST code

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mongodb/dbx-php What's your opinion on the formatting of this tutorial? It's actually steps.

Copy link
Member

@jmikola jmikola Apr 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No objections if you feel it's worth the effort.

Please make sure that formatting doesn't clash with "AWS Credentials", which has a numbered list within. I'm not expecting any issue nesting a list within the RST step syntax -- just a request to confirm the rendered output looks presentable.

Edit: looking at the Kafka tutorial, I consider it less useful that the steps aren't incorporated into the "On this page" navigation. Given that, I'd lean toward no changes.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think skipping steps formatting is fine and more efficient with time. The issue I was focusing on was missing punctuation. Perhaps it could be something to experiment with in a future PR!


.. code-block:: bash

serverless deploy


The application will not work unless you define the ``MONGODB_URI`` environment variable.

AWS Credentials
---------------

Atlas supports passwordless authentication with AWS credentials. In any Lambda function,
AWS sets environment variables that contains the access token and secret token with
the role assigned to deployed function.

Set up :manual:`unified AWS Access </atlas/security/set-up-unified-aws-access/>`:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use the :atlas: role unless it's overridden by extlinks:

https://github.com/mongodb/snooty-parser/blob/main/snooty/rstspec.toml#L1290-L1292

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Atlas links doesn't work.
image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use the :atlas: role unless it's overridden by extlinks:

Does the very existence of extlinks in conf.py prevent us from using any of the roles defined in main/snooty/rstspec.toml?

mongodb/docs-php-library#57 was going to introduce atlas to extlinks, but it's presently not there.

As I mentioned in Slack, we'd need a custom role for :php: to link to PHP.net pages. I'm not a bit worried that reducing conf.py to

extlinks = {
    'php': ('https://php.net/%s', '')
}

...might mean we lose access to :manual: as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard my last comment. @schmalliso confirmed that conf.py is ignored by Snooty. All of the roles we need are already defined in main/snooty/rstspec.toml (including :php:).

@GromNaN: I'm not sure why :atlas: isn't working. Perhaps there's some other configuration where specific roles from rstspec.toml need to be enabled for a project? This seems like a question for #ask-docs-platform.


1. Open the Lambda function in the AWS console
2. In "Configuration > Permission", copy the "Role name"
3. Open the MongoDB Atlas project
4. Go to "Security > Database Access"
5. Click "Add a new Database User"
6. Select Authentication Method: "AWS IAM", type "IAM Role" and paste the role name in "AWS Role ARN".
7. Add "Built-in Role": "Read and write any database"
8. Validate by clicking on "Add user".

Now that the permissions have been configured, the lambda function is allowed to access
your Atlas cluster. You can configure your application with the Atlas endpoint.

Update the ``serverless.yml`` file to pass the environment variable ``MONGODB_URI``

.. code-block:: yaml

provider:
environment:
MONGODB_URI: "mongodb+srv://cluster0.example.mongodb.net/"


The value can be found in "Atlas > Deployment > Database > Connect". Select "3. AWS IAM".
Remove the ``<AWS access key>:<AWS secret key>`` part from the URI, the credentials
will be read from environment variables.

.. code-block:: bash

serverless deploy
11 changes: 11 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@

<!-- Disable forbidden annotation sniff as excluding @api from the list doesn't work -->
<exclude name="SlevomatCodingStandard.Commenting.ForbiddenAnnotations.AnnotationForbidden" />

<!-- Example file using HTML templating -->
<exclude name="Generic.Files.InlineHTML.Found">
<exclude-pattern>docs/examples/*/index.php</exclude-pattern>
</exclude>
<exclude name="SlevomatCodingStandard.ControlStructures.BlockControlStructureSpacing.IncorrectLinesCountAfterControlStructure">
<exclude-pattern>docs/examples/*/index.php</exclude-pattern>
</exclude>
<exclude name="Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps">
<exclude-pattern>docs/examples/*/index.php</exclude-pattern>
</exclude>
</rule>


Expand Down