Skip to content

Commit

Permalink
Merge pull request #115 from azavea/tt/rest-api-design
Browse files Browse the repository at this point in the history
  • Loading branch information
rajadain authored Oct 10, 2022
2 parents cf2f6ad + 33e064e commit 100e8d0
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add RTK Query [#101](https://github.com/azavea/iow-boundary-tool/pull/101)
- Add navigation bar and logout button [#109](https://github.com/azavea/iow-boundary-tool/pull/109)
- Style submission detail page [#104](https://github.com/azavea/iow-boundary-tool/pull/104)
- Add ADR for REST API [#115](https://github.com/azavea/iow-boundary-tool/pull/115)

### Changed

Expand Down
78 changes: 78 additions & 0 deletions doc/arch/adr-002-rest-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Boundary Sync REST API Design

## Context

Based on the [data model](./adr-001-data-models.md), the following REST API design is proposed to access it:

### Authentication

| Path | Method | Body | Authentication | Responses | Notes |
| --------------- | ------ | --------- | -------------- | ----------------------------------------------------- | -------------------------------------------- |
| `/auth/login/` | GET | - | Allow Any | 200 OK,<br />401 Not Authorized | Returns loging JSON if current session valid |
| `/auth/login/` | POST | `{ ... }` | Allow Any | 200 OK,<br />400 Bad Request,<br />401 Not Authorized | Used for starting new valid session |
| `/auth/logout/` | POST | - | Logged In User | 200 OK | Used for logging out |

Also present are `/auth/password/reset/` and `/auth/password/reset/confirm/` endpoints that come from `dj_rest_auth`.

### Boundaries

| Path | Method | Body | Authentication | Responses | Notes |
| ------------------------------------------- | ------ | ------------------------ | -------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `/boundaries/` | GET | - | Logged In User | 200 OK | Returns list of all boundaries the user has access to |
| `/boundaries/?utilities=1,3,5,8` | GET | - | Logged In User | 200 OK,<br />401 Not Authorized | Returns list of boundaries in the given utilities. If the user does not have access to that utility, returns a 401 |
| `/boundaries/` | POST | `{ ... }` | Contributor | 201 Created,<br />400 Bad Request,<br />401 Not Authorized | Creates a new boundary if the payload is correct and the user is authorized |
| `/boundaries/{id}/` | GET | - | Logged In User | 200 OK,<br />404 Not Found | Returns boundary details if the user has access to it, else 404s. Includes all details about the boundary. |
| `/boundaries/{id}/shape/` | PUT | `{ ... }` | Contributor | 200 OK,<br />404 Not Found | Updates the latest submission's shape |
| `/boundaries/{id}/reference-images/` | POST | `{ ... }` | Contributor | 200 OK,<br />404 Not Found | Adds a new reference image to the boundary |
| `/boundaries/{id}/reference-images/{id}/` | PUT | `{ ... }` | Contributor | 200 OK,<br />404 Not Found | Updates a reference image |
| `/boundaries/{id}/submit/` | POST | `{ notes }` | Contributor | 200 OK,<br />404 Not Found | Submits the boundary |
| `/boundaries/{id}/review/` | POST | `{ notes, annotations }` | Validator | 200 OK,<br />404 Not Found | Reviews a boundary |
| `/boundaries/{id}/review/annotations/{id}/` | PUT | `{ annotation }` | Validator | 200 OK,<br />404 Not Found | Updates an annotation in the latest review. Older reviews are read-only, so no need to specify review id. |
| `/boundaries/{id}/draft/` | POST | - | Contributor | 200 OK,<br />404 Not Found | Creates a new draft submission for a boundary after a review |
| `/boundaries/{id}/approve/` | POST | - | Validator | 200 OK,<br />404 Not Found | Approves a boundary |
| `/boundaries/{id}/unapprove/` | POST | - | Validator | 200 OK,<br />404 Not Found | Unapproves a boundary |

### User

| Path | Method | Body | Authentication | Responses | Notes |
| -------------------- | ------ | --------- | -------------- | -------------------------- | ---------------------------------- |
| `/user/{id}/profile` | PUT | `{ ... }` | Contributor | 200 OK,<br />404 Not Found | Update contributor contact details |

## Notes

Any thing that a Contributor or Validator can do, an Administrator can also do.

A payload Body of `-` means that there is no body required. A payload Body of `{ ... }` means that there is a required body, but is not elaborated here.

All endpoints that are marked as requiring a Logged In User will also return 401 Not Authorized if accessed without proper credentials.

When we return `404 Not Found` for objects that the User does not have permissions to, we're using a pattern like this:

```python
@permission_classes((IsAuthenticated,))
def get_boundary(request, id):
user = request.user
boundary = get_object_or_404(Boundary, id)
submission = boundary.get_latest_submission_for(user)

serializer = SubmissionSerializer(submission)
return Response(serializer.data)
```

where `get_latest_submission_for` is along these lines:

```python
class Boundary(models.Model):
...

def get_latest_submission_for(self, user):
if user.role == CONTRIBUTOR:
if self.utility not in user.utilities:
raise Http404

if user.role == VALIDATOR:
if self.utility.state not in user.states:
raise Http404

return self.submissions.latest('created_at')
```

0 comments on commit 100e8d0

Please sign in to comment.