Material list is a system that stores material identifiers on behalf of library patrons. This allows patrons to build a check list of materials they want to remember or are particularily interested in.
Data can be accessed through a public API documented in OpenAPI 3 format.
Access to the API is controlled by Adgangsplatformen - a single sign-on solution for public libraries in Denmark.
Material-list requires a host with the following software:
- Nginx 1.17
- PHP 7.3
- Mysql 5.7+ compatible database
Individual components can be swapped for relevant alternatives. Apache can be used instead of Nginx. Any database supported by Laravel such as PostgresSQL, SQLite and SQL Server can replace MariaDB.
The access token must be retrieved from Adgangsplatformen by using one of two types of grant:
Usage of Adgangsplatform requires a valid client id and secret which must be obtained from your library partner or directly from DBC, the company responsible for running Adgangsplatfomen.
Example for retrieving an access token using password grant:
curl -X POST https://login.bib.dk/oauth/token -d 'grant_type=password&password=[patron-password]&username=[patron-username]&agency=[patron-library-agency-id]&client_id=[client-id]&client_secret=[client-secret]'
This will return a data structure containing the access token:
{
"access_token":"abcd1234",
"token_type":"Bearer",
"expires_in":2591999
}
The access token must be provided as a Bearer token in the Authorization header in requests to the Material List API. When accessing the API Material List will validate tokens by retrieving the corresponding user data from Adgangsplaformen.
Token validity can be tested separately by trying to retrieve user data manually:
curl https://login.bib.dk/userinfo -H 'Authorization: Bearer [access-token]'
If a token cannot be used to retrieve user data this way it cannot be used to access Material List either.
Materials are added to the list in the form of a PID.
curl -X PUT https://test.materiallist.dandigbib.org/list/default/870970-basis:50936155 -H 'Authorization: Bearer abcd1234'
Requests should return HTTP response code 201 indicating that the material has been added to the list.
If the token is not valid then HTTP response code 401 is returned.
curl -X GET https://test.materiallist.dandigbib.org/list/default -H 'Authorization: Bearer abcd1234'
This should return a data structure containing all materials on the list:
{
"id": "default",
"materials": [
"870970-basis:50936155"
]
}
In order to run local development you need:
- Docker
- Preferably support for
VIRTUAL_HOST
environment variables for Docker containers. Examples: Dory (OSX) ornginx-proxy
.
If you are using a mac/OSX it is recommended to use nfs on the mounted volumes in docker-compose.
Copy the docker-compose.mac-nfs.yml:
$ cp docker-compose.mac-nfs.yml docker-compose.override.yml
And follow this guide in order to set it up.
- Run docker-compose up
- Copy
.env.example
to.env
and adjust the configuration. - Enter the app container by running:
docker-compose exec app sh
- Run
composer install
to install dependencies. - Run
./artisan migrate:fresh
to create the database tables. - The application is now ready to be tested.
- The application can be reached on the host at: http://ddb-material-list.docker
The configuration may be passed via environment variables, but the
.env
file allows for easy configuration of all variables. See
.env.example
for configuration options.
The project uses the Git Flow model for branching.
GitHub Actions runs tests and checks when new code is pushed.
Pushes to master
and develop
deploys the version to the prod
and
test
environments respectively. The deploys are also handle by
GitHub Actions.
The application code is in the App
namespace and located in the
app
directory.
Application bootstrapping is in bootstrap/app.php
, it sets up the
container, middleware and service providers, and points at the route
file.
Routes are defined in routes/web.php
. They all point to a method in
a Controller class. See the Lumen documentation on
routing for more
information.
The controller classes is defined in App\Http\Controllers
. The
controller methods handling requests gets the URL path placeholders as
arguments, and typehinted arguments are auto-wired from the container.
They can return array data (which is automatically transformed into a
JSON response), a Illuminate\Http\Response
(which subclasses
Symfony\Component\HttpFoundation\Response
), or throw an exception
(which is converted to an appropriate response by the error handler).
See the Lumen documentation on controllers for more information.
The application uses middleware from the oauth2-adgangsplatformen
package to enforce bearer token authentication for routes.
This ensures that the return value of the Request::user()
method of
the current request is an instance of an AdgangsplatformenUser
object corresponding to the token.
Requests without valid tokens are rejected.
The App\Exceptions\Handler
handles exceptions thrown by the
controllers. It converts
Symfony\Component\HttpKernel\Exception\HttpException
and its
subclasses into the corresponding responses (NotFoundHttpException
into a 404, for instance). For
Illuminate\Http\Exceptions\HttpResponseException
(which is an
exception that encapsulates a Response
) it simply uses the
exceptions response. Everything else causes a "500 Internal error"
response, unless the APP_DEBUG
environment variable is true, in
which case it serves the exception message as text/plain
to ease
debugging.
The database schema is defined in database/migrations
.
See the Laravel documentation on migrations for more information.
Queries are done with the Laravel query builder. The application does not use an ORM.
See the Lumen documentation on databases for more information.
Most tests are done as behavior test using Behat. The features are in
tests/features
while the context classes reside in tests/contexts
,
and the tests can be run with ./vendor/bin/behat
.
The context doesn't interact with the application over HTTP, rather
the application is booted inside the test for each scenario. This is
the same way that unit tests of controllers is done, in fact the
context is using the same
Laravel\Lumen\Testing\Concerns\MakesHttpRequests
trait that
Laravel\Lumen\Testing\TestCase
uses to construct the right request
objects.
This also makes code coverage collection simpler. Behat writes
coverage to coverage
, which can be rendered to HTML with
./vendor/bin/phpcov merge --html=./coverage/html ./coverage
.
To ensure the integrity and quality of the specification we lint it using Speccy.
- Install Speccy:
npm install --global speccy
- Run Speccy:
speccy lint material-list.yaml
Run docker compose run app speccy lint material-list.yaml
.
API specification tests are done by generating requests as documented by the specification and testing if the application reacts as documented. Dredd is used for this.
To install Dredd, run: npm install --global dredd@12
.
Running Dredd is as simple as dredd
. Dredd is configured to run
php -S 0.0.0.0:8080 -t public
to start the server, which simply runs the
application using the PHP built-in webserver.
In order to ensure the right conditions for each test, Dredd uses a
hooks file (tests/dredd/hooks.php
), which allows for setting
fixtures or modifying the requests/response.
To get the names of requests (for use in hook file), use dredd --names
. Getting dredd to display any output from the hook file (for
debugging), you need to run it in verbose mode: dredd --loglevel=debug
.
Run docker compose run app dredd
.
Unit tests are primarily used to test parts that are difficult to test
by the previous methods, unexpected exception handling for instance.
Run ./vendor/bin/phpunit
to run the test suite.
Create namespace with labels to allow traffic.
kubectl create namespace material-list
kubectl label namespaces/ingress networking/namespace=ingress
kubectl label namespaces/material-list networking/namespace=material-list
This repository comes with helm chats for deployment to kubernetes cluster in infrastructure/material_list
which
requires that you have a local secrets.yml
in the templates folder. As this file contains sensitive information
you can use the secrects.example.yaml
file as a template for the required values.
The following command can be used to install the chart
helm upgrade --install --namespace=material-list material-list infrastructure/material_list/ --set ingress.domain=prod.materiallist.dandigbib.org
Copyright (C) 2019 Danskernes Digitale Bibliotek (DDB)
This project is licensed under the GNU Affero General Public License - see the LICENSE.md file for details