Skip to content

Commit adecdf7

Browse files
committed
NEW Add re-usable UuidableExtension
1 parent 31599b0 commit adecdf7

File tree

2 files changed

+76
-35
lines changed

2 files changed

+76
-35
lines changed

README.md

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,21 @@ the [https://github.com/Level51/silverstripe-jwt-utils/](JWTUtils) module.
2323

2424
_app/\_config/api.yml_
2525

26-
```
26+
```yml
2727
Level51\JWTUtils\JWTUtils:
2828
secret: 'replace-this-with-a-jwt-secret-for-jwt'
2929
lifetime_in_days: 365
3030
renew_threshold_in_minutes: 60
3131
```
3232
33-
Next step is to setup the routing for the API. You can modify the name of the
34-
routes as required for the project. At the very least you would have a
35-
project-specific end point which would subclass the `ApiController` for example,
33+
Next step is to setup the routing for the API. You can modify the name of the
34+
routes as required for the project. At the very least you would have a
35+
project-specific end point which would subclass the `ApiController` for example,
3636
`MyProjectsApi`.
3737

3838
_app/\_config/routes.yml_
3939

40-
```
40+
```yml
4141
SilverStripe\Control\Director:
4242
rules:
4343
'api/v1/auth/$Action': 'FullscreenInteractive\Restful\Controllers\AuthController'
@@ -50,7 +50,7 @@ list of all projects, logged in ADMIN users can `POST api/v1/projects/create`
5050

5151
_app/src/Project.php_
5252

53-
```
53+
```php
5454
<?php
5555
5656
use FullscreenInteractive\Restful\Interfaces\ApiReadable;
@@ -63,24 +63,24 @@ class Project extends DataObject implements ApiReadable
6363
'Title' => 'Varchar(100)',
6464
'Date' => 'DBDate'
6565
];
66-
67-
private static $has_one = [
68-
'Author' => Member::class
69-
];
70-
66+
67+
private static $has_one = [
68+
'Author' => Member::class
69+
];
70+
7171
public function toApi(): array
7272
{
73-
return [
74-
'title' => $this->Title,
75-
'date' => $this->dbObject('Date')->getTimestamp()
76-
];
77-
}
73+
return [
74+
'title' => $this->Title,
75+
'date' => $this->dbObject('Date')->getTimestamp()
76+
];
77+
}
7878
}
7979
```
8080

8181
_app/src/MyProjectsApi.php_
8282

83-
```
83+
```php
8484
<?php
8585
8686
class MyProjectsApi extends FullscreenInteractive\Restful\Controllers\ApiController
@@ -101,7 +101,7 @@ class MyProjectsApi extends FullscreenInteractive\Restful\Controllers\ApiControl
101101
public function createProject()
102102
{
103103
$this->ensurePOST();
104-
104+
105105
$member = $this->ensureUserLoggedIn([
106106
'ADMIN'
107107
]);
@@ -116,7 +116,7 @@ class MyProjectsApi extends FullscreenInteractive\Restful\Controllers\ApiControl
116116
$project = new Project();
117117
$project->Title = $title;
118118
$project->Date = $date;
119-
$project->AuthorID = $member->ID;
119+
$project->AuthorID = $member->ID;
120120
$project->write();
121121
122122
return $this->returnJSON([
@@ -127,7 +127,7 @@ class MyProjectsApi extends FullscreenInteractive\Restful\Controllers\ApiControl
127127
public function deleteProject()
128128
{
129129
$this->ensurePOST();
130-
130+
131131
$member = $this->ensureUserLoggedIn([
132132
'ADMIN'
133133
]);
@@ -145,10 +145,10 @@ class MyProjectsApi extends FullscreenInteractive\Restful\Controllers\ApiControl
145145
]);
146146
}
147147
148-
if ($project->canDelete($member)) {
149-
$project->delete();
150-
}
151-
148+
if ($project->canDelete($member)) {
149+
$project->delete();
150+
}
151+
152152
return $this->success();
153153
}
154154
}
@@ -161,7 +161,7 @@ receive a token the user must first exchange their username / password over
161161
basic authenication by making a `POST` request with the credentials. Usually
162162
this is some form of javascript request e.g
163163

164-
```
164+
```js
165165
fetch('/api/v1/auth/token', {
166166
method: "POST",
167167
headers: {
@@ -177,23 +177,23 @@ The response from that request with either be an error code (> 200) or if user
177177
and password is correct, a 200 response containing the JWT. The token and
178178
related meta data can be saved securely client side for reuse.
179179

180-
```
180+
```js
181181
{
182-
"token": "eyJ0eXAiOiJKV1QiL...",
183-
"member": {
184-
"id": 1,
185-
"email": "[email protected]",
186-
"firstName": "Julian",
187-
"surname": "Scheuchenzuber"
188-
}
182+
"token": "eyJ0eXAiOiJKV1QiL...",
183+
"member": {
184+
"id": 1,
185+
"email": "[email protected]",
186+
"firstName": "Julian",
187+
"surname": "Scheuchenzuber"
188+
}
189189
}
190190
```
191191

192192
If a user's token is invalid, or expired a *401* error will be returned. To
193193
validate a users token use the `verify` endpoint - this will check the token and
194194
renew the token if required.
195195

196-
```
196+
```js
197197
fetch('/api/v1/auth/verify', {
198198
method: "GET",
199199
headers: {
@@ -206,7 +206,7 @@ fetch('/api/v1/auth/verify', {
206206

207207
The token can then be used to sign API calls as the `Bearer` header.
208208

209-
```
209+
```js
210210
fetch('/api/v1/projects/createProject', {
211211
method: "POST",
212212
headers: {
@@ -218,6 +218,23 @@ fetch('/api/v1/projects/createProject', {
218218
})
219219
```
220220

221+
## UUIDs
222+
223+
https://stackoverflow.com/questions/56576985/is-it-a-bad-practice-to-expose-the-database-id-to-the-client-in-your-rest-api/56577271
224+
225+
When designing an API you may wish to avoid exposing your internal ID's to
226+
in responses.
227+
228+
To add a UUID field to your object add the following extension to your model
229+
230+
```php
231+
private static $extensions = [
232+
UuidableExtension::class
233+
];
234+
```
235+
236+
A UUID will be generated on an objects `onBeforeWrite()` .
237+
221238
## API Documentation
222239

223240
Todo but it's not massive. See `ApiController` for now.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace FullscreenInteractive\Restful\Extensions;
4+
5+
use Ramsey\Uuid\Uuid;
6+
use SilverStripe\ORM\DataExtension;
7+
8+
class UuidableExtension extends DataExtension
9+
{
10+
private static $db = [
11+
'UUID' => 'Varchar(200)'
12+
];
13+
14+
private static $indexes = [
15+
'UUID' => true
16+
];
17+
18+
public function onBeforeWrite()
19+
{
20+
if (!$this->owner->UUID) {
21+
$this->owner->UUID = Uuid::uuid4()->toString();
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)