Skip to content
Permalink
Browse files

Bulk link creation API (#443)

* Add bulk shortening API endpoint & create controller methods
* Update documentation
* Remove space %20 mapping for bulk API
  • Loading branch information...
cydrobolt committed Apr 21, 2018
1 parent b29c5d5 commit 1fb607ba631cf9a6c9eb7ed922bf723d2dfe03f3
@@ -66,13 +66,13 @@ public static function createLink($long_url, $is_secret=false, $custom_ending=nu
// has custom ending
$ending_conforms = LinkHelper::validateEnding($custom_ending);
if (!$ending_conforms) {
throw new \Exception('Sorry, but custom endings
throw new \Exception('Custom endings
can only contain alphanumeric characters, hyphens, and underscores.');
}
$ending_in_use = LinkHelper::linkExists($custom_ending);
if ($ending_in_use) {
throw new \Exception('Sorry, but this URL ending is already in use.');
throw new \Exception('This URL ending is already in use.');
}
$link_ending = $custom_ending;
@@ -97,7 +97,6 @@ public static function createLink($long_url, $is_secret=false, $custom_ending=nu
$link->is_api = $is_api;
if ($creator) {
// if user is logged in, save user as creator
$link->creator = $creator;
}
@@ -7,12 +7,22 @@
use App\Exceptions\Api\ApiException;
class ApiLinkController extends ApiController {
protected function getShortenedLink($long_url, $is_secret, $custom_ending, $link_ip, $username, $response_type) {
try {
$formatted_link = LinkFactory::createLink(
$long_url, $is_secret, $custom_ending, $link_ip, $username, false, true);
}
catch (\Exception $e) {
throw new ApiException('CREATION_ERROR', $e->getMessage(), 400, $response_type);
}
return $formatted_link;
}
public function shortenLink(Request $request) {
$response_type = $request->input('response_type');
$user = $request->user;
// Validate parameters
// Encode spaces as %20 to avoid validator conflicts
$validator = \Validator::make(array_merge([
'url' => str_replace(' ', '%20', $request->input('url'))
], $request->except('url')), [
@@ -23,20 +33,69 @@ public function shortenLink(Request $request) {
throw new ApiException('MISSING_PARAMETERS', 'Invalid or missing parameters.', 400, $response_type);
}
$long_url = $request->input('url'); // * required
$is_secret = ($request->input('is_secret') == 'true' ? true : false);
$formatted_link = $this->getShortenedLink(
$request->input('url'),
($request->input('is_secret') == 'true' ? true : false),
$request->input('custom_ending'),
$request->ip(),
$user->username,
$response_type
);
return self::encodeResponse($formatted_link, 'shorten', $response_type);
}
public function shortenLinksBulk(Request $request) {
$response_type = $request->input('response_type', 'json');
$request_data = $request->input('data');
$user = $request->user;
$link_ip = $request->ip();
$custom_ending = $request->input('custom_ending');
$username = $user->username;
try {
$formatted_link = LinkFactory::createLink($long_url, $is_secret, $custom_ending, $link_ip, $user->username, false, true);
if ($response_type != 'json') {
throw new ApiException('JSON_ONLY', 'Only JSON-encoded responses are available for this endpoint.', 401, $response_type);
}
catch (\Exception $e) {
throw new ApiException('CREATION_ERROR', $e->getMessage(), 400, $response_type);
$links_array_raw_json = json_decode($request_data, true);
if ($links_array_raw_json === null) {
throw new ApiException('INVALID_PARAMETERS', 'Invalid JSON.', 400, $response_type);
}
return self::encodeResponse($formatted_link, 'shorten', $response_type);
$links_array = $links_array_raw_json['links'];
foreach ($links_array as $link) {
$validator = \Validator::make($link, [
'url' => 'required|url'
]);
if ($validator->fails()) {
throw new ApiException('MISSING_PARAMETERS', 'Invalid or missing parameters.', 400, $response_type);
}
}
$formatted_links = [];
foreach ($links_array as $link) {
$formatted_link = $this->getShortenedLink(
$link['url'],
(array_get($link, 'is_secret') == 'true' ? true : false),
array_get($link, 'custom_ending'),
$link_ip,
$username,
$response_type
);
$formatted_links[] = [
'long_url' => $link['url'],
'short_url' => $formatted_link
];
}
return self::encodeResponse([
'shortened_links' => $formatted_links
], 'shorten_bulk', 'json');
}
public function lookupLink(Request $request) {
@@ -66,6 +66,7 @@
/* API shorten endpoints */
$app->post('action/shorten', ['as' => 'api_shorten_url', 'uses' => 'ApiLinkController@shortenLink']);
$app->get('action/shorten', ['as' => 'api_shorten_url', 'uses' => 'ApiLinkController@shortenLink']);
$app->post('action/shorten_bulk', ['as' => 'api_shorten_url_bulk', 'uses' => 'ApiLinkController@shortenLinksBulk']);
/* API lookup endpoints */
$app->post('action/lookup', ['as' => 'api_lookup_url', 'uses' => 'ApiLinkController@lookupLink']);
@@ -2,8 +2,8 @@
-----------------------------

## API keys
To authenticate a user to Polr, you will need to provide an API key along with
each request to the Polr API, as a GET or POST parameter. (e.g `?key=API_KEY_HERE`)
To authenticate a user to Polr, you *must* provide an API key along with
each request to Polr API endpoints, as a GET or POST parameter. (e.g `?key=API_KEY_HERE`)

## Assigning an API key
To assign an API key, log on from an administrator account, head over to the "Admin"
@@ -26,11 +26,9 @@ See [API endpoints](#api-endpoints) for more information on the actions.

## Response Type
The Polr API will reply in `plain_text` or `json`. The response type can be
set by providing the `response_type` argument to the request. If not provided,
the response type will default to `plain_text`.

Data endpoints will only return JSON-formatted data and will default to `json` if no
`response_type` is provided.
set by providing the `response_type` argument to the request. If this argument is not provided,
the response type will default to either `plain_text` or `json` depending
on the endpoint.

Example `json` responses:
```
@@ -84,7 +82,61 @@ Response:
}
```
Remember that the `url` argument must be URL encoded.
The `url` argument must be URL encoded.
### /api/v2/action/shorten_bulk
_`POST` only_
Arguments:
- `data`: a string containing a JSON-encoded object with an array of links
Example `data` argument:
```json
{
"links": [
{
"url": "https://polrproject.org/"
},
{
"url": "https://youtube.com",
"is_secret": true
},
{
"url": "https://github.com/cydrobolt/polr",
"custom_ending": "polrgithub"
}
]
}
```

Response: A JSON-encoded object with a list of shortened links.

Example response:
```
{
"action": "shorten_bulk",
"result": {
"shortened_links": [
{
"long_url": "https://polrproject.org/",
"short_url": "http://demo.polr.me/81"
},
{
"long_url": "https://youtube.com",
"short_url": "http://demo.polr.me/84/b496"
},
{
"long_url": "https://github.com/cydrobolt/polr",
"short_url": "http://demo.polr.me/polrgithub"
}
]
}
}
```



### /api/v2/action/lookup
The `lookup` action takes a single argument: `url_ending`. This is the URL to
@@ -8,6 +8,8 @@ it to `true` in `.env`

`MISSING_PARAMETERS`: Invalid or missing parameters.

`INVALID_PARAMETERS`: Invalid parameters.

`NOT_FOUND`: Object not found.

`ACCESS_DENIED`: User is not authorized to access the object.
@@ -23,7 +23,7 @@ you may be interested in looking at a [legacy 1.x release](https://github.com/cy
- JSON PHP Extension
- PHP curl extension

## Downloading the source code
## Download the source code

If you would like to download a stable version of Polr, you may check out [the releases page](https://github.com/cydrobolt/polr/releases).

@@ -49,7 +49,7 @@ $ chown -R apache polr
$ chcon -R -t httpd_sys_rw_content_t polr/storage polr/.env
```

## Installing using `composer`
## Install `composer` dependencies

```bash
# download composer package
@@ -177,7 +177,7 @@ server {
To run Polr on another HTTP server or on shared hosting, you will need to set the home
directory to `/PATH_TO_POLR/public`, not the root Polr folder.

## Creating the database
## Create the database

### MySQL

0 comments on commit 1fb607b

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.