This is a Node.js-based API, backed in MySQL, that contains map pins submitted by users and provided by users' training centers.
This API is meant to support a mobile app.
PONToon is an exciting project that will use a range of new and developing technologies such as games development, 3D/virtual reality, social media and web/mobile apps to engage, support and up-skill women in order to aid their employment opportunities.
The project is centred around community development, social and economic inclusion and equality. It aims to produce a method of working that's not only scalable and transferrable but also applicable to broader demographic sets and geographical regions for continuing impact.
PONToon will employ digital tools and methods to provide equal access to training and employment services in response to the digital skills shortage existing across all sectors of work. PONToon will provide a more flexible approach to existing training/employment services increasing efficiency and quality due to the dual effect of the toolkit enhancing both technical digital skills and core competencies for employment.
Budget received from the France (Channel) England Programme: €4 million ERDF
Total Project Budget: €5.79 million
Project Duration: 3.5 yearsIf you want to install the API at pontoonapps.com:
- create a Node.js application in the cpanel
npm installto load all dependencies- make sure there's a MySQL database user available for this API implementation to use
- the database must contain the table
users(as per PONToonapps.com) - the database must contain the table
map_pins(seesql-init.sqlto create it) - the database user should be suitably constrained (only select from
users, select/insert/update/delete inmap_pins)
- the database must contain the table
- edit
config.json(possibly create one fromconfig-template.json)- create and give API keys to app developer(s)
The API runs at https://pontoonapps.com/community-api (referred to as <root> below). Data structures and authentication mechanisms are detailed in further sections.
The API has two versions: v1 (not indicated in the URL) used pin name to identify pins; v2 uses unique database-generated ID values instead.
The main routes are:
- GET
<root>/v2/pins– return array of all pins visible to this user - POST
<root>/v2/pins– add a user pin (accepts JSON)- if the JSON includes an ID, this is an update operation (existence of that ID among this user's pins is checked)
- if the JSON does not include an ID, this is an add operation (creates a new pin)
- returns 200 OK on success, the new/updated pin in the response
- returns 409 Conflict if an update is requested but the ID doesn't exist
- returns 400 Bad Request when data is malformed
- POST
<root>/v2/pins/delete– remove a pin identified by ID and created by the calling user (accepts JSON)- the incoming JSON should only be
{ "id": value } - a user can only delete their own pins
- returns 204 No Content on success
- returns 409 Conflict if the ID doesn't exist or doesn't belong to this user
- returns 400 Bad Request when data is malformed
- the incoming JSON should only be
Original (v1) API:
- GET
<root>/pins– return array of all pins visible to this user - POST
<root>/pins– add a user pin (accepts JSON)- if the user already has a pin with this name, the pin information is all updated
- returns 204 No Content on success
- returns 400 Bad Request when data is malformed
- POST
<root>/pins/delete– remove a pin identified by name and created by the calling user (accepts JSON)- the incoming JSON should only be
{ "name": "..." } - a user can only delete their own pins
- if the user has multiple pins with the same name (v2), all will be deleted by this v1 call
- returns 204 No Content on success (even if pin with the name didn't exist)
- returns 400 Bad Request when data is malformed
- the incoming JSON should only be
A pin is represented in the API with the following data structure:
{
id: (API v2) opaque (generated by server, unique for the user),
name: String (max 255 chars in v2,
in v1 max 40 chars and unique for the user)
latitude: Number,
longitude: Number,
category: (optional) Number,
description: (optional) String (max 255 chars),
phone: (optional) String (max 25 chars),
website: (optional) String (max 255 chars),
email: (optional) String (max 255 chars),
address_line_1: (optional) String (max 255 chars),
address_line_2: (optional) String (max 255 chars),
postcode: (optional) String (max 12 chars),
notes: (optional) String (max 255 chars),
}
A pin returned by the API can also have a field userPin (Boolean) – true if this pin was submitted by the user, and false if it comes from a training centre. Training centre pins also have training_centre_email so the app can show which training centre provided this pin.
(v1 and v2 APIs are the same, the /v2 part of the URL is optional)
These routes return 403 Forbidden if the current user is not a training centre (role "recruiter").
- GET
<root>[/v2]/training-centre/users– return array of emails of the users assigned to the authenticated training centre - POST
<root>[/v2]/training-centre/users– add (assign) and remove (unassign) users to this training centre. Input data:{ add: (optional) [ email strings ], remove: (optional) [ email strings ], }- removal is processed first, then addition – if both arrays contain the same email address, the user will be added;
- users that do not exist in the database will be ignored (the client should report the email addresses that weren't added);
- removing users that were not assigned to the training centre is also ignored;
- returns the result list of users assigned to the training centre (like the GET method above).
(v1 and v2 APIs are the same, the /v2 part of the URL is optional)
These routes return 403 Forbidden if the current user is not a normal user (i.e. if they are a training centre).
- GET
<root>[/v2]/user/training-centres– return array of training centres of the given user (same data structure as intraining_centresat<root>/loginbelow) - POST
<root>[/v2]/user/training-centres/remove– remove the calling user from the given training centre (accepts JSON)- the incoming JSON should only be
{ "email": "..." } - returns 204 No Content on success (even if the user wasn't in the given training centre)
- returns 400 Bad Request when data is malformed
- the incoming JSON should only be
- GET
<root>/– returns a successful response if the API is running and supports v1 (no authentication needed) - GET
<root>/v2/– returns a successful response if the API supports v2 (no authentication needed) - GET
<root>[/v2]/ping– returns a successful response if the API key is accepted (only API key needed) - GET
<root>[/v2]/login– (optional) returns information about the user, in the following format:{ role: "user" or "recruiter", training_centres: [ { email: String, name: { first: String, last: String, } }, … ] }- notes
- in pontoonapps, training centres have "recruiter" role;
training_centresis there only if the role is "user"; if the user is not assigned to any training centre, it will be an empty array.
- notes
The API must only be accessed over HTTPS.
The API uses an API key provided as a URL query parameter apiKey; this key should be kept privately by the developers of the mobile app(s). If a key is found to be misused, it can be revoked. With the wrong key, the API returns 403 Forbidden.
If your key is ABCDEFGH, you can check the API at https://pontoonapps.com/community-api/ping?apiKey=ABCDEFGH
Users in the app use their pontoonapps.com account details: the API accepts pontoonapps.com "job seekers" (internally under the role user) and "recruiters".
The app uses these account details (email and password) with HTTP Basic Authentication in all API requests (except ping). Without valid credentials, the API returns 401 Unauthorized.
Any registered user can request their map pins at <root>[/v2]/pins; if they have never submitted any, this will return an empty array.
NB: The login API call is only for checking role and training centres and is not required; there are no sessions and every API request contains the credentials.
- pontoonapps.com always uses HTTPS, which should be sufficient for network security (in particular, it should be OK to use Basic Auth)
- pontoonapps.com recruiters act as training centres for the community map API.
- recognized API keys probably could be in the database rather than in the config file
- check that in cpanel we can't have more fine-grained access control than db-wide privileges
iOS/Android availible here: https://github.com/pontoonapps/Community-Map-Apps
Web version availible here: https://github.com/pontoonapps/Community-Map
Visit our website for more information about the PONToon Project
