UNPKG

bookmonkey-api

Version:

A simple backend for the BookMonkey example application.

632 lines (591 loc) 19.8 kB
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Bookmonkey API</title> <meta name="robots" content="noindex, follow" /> <link rel="stylesheet" href="bootstrap.min.css" /> <link rel="stylesheet" href="highlight.androidstudio.css" /> <script src="highlight.pack.js"></script> <script> hljs.initHighlightingOnLoad(); </script> </head> <body> <!-- Navigation --> <nav class="navbar navbar-toggleable navbar-inverse bg-primary"> <div class="container"> <a class="navbar-brand" href="#">Bookmonkey API</a> <ul class="navbar-nav mr-auto"> <li class="nav-item"> <a class="nav-link" href="#list">List</a> </li> <li class="nav-item"> <a class="nav-link" href="#detail">Detail</a> </li> <li class="nav-item"> <a class="nav-link" href="#create">Create</a> </li> <li class="nav-item"> <a class="nav-link" href="#update">Update</a> </li> <li class="nav-item"> <a class="nav-link" href="#delete">Delete</a> </li> <li class="nav-item"> <a class="nav-link" href="#operations">Further Operations</a> </li> <li class="nav-item"> <a class="nav-link" href="#authentication">Authentication</a> </li> <li class="nav-item"> <a class="nav-link" href="#users">User Relation</a> </li> <li class="nav-item"> <a class="nav-link" href="#guarded_routes">Guarded Routes</a> </li> </ul> </div> </nav> <!-- Content --> <main class="container mt-4"> <!-- Book List --> <h2 id="list">Book List</h2> <p>GET <a href="/books" target="_blank">/books</a></p> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> [ { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png" }, … ] </code> </pre> <!-- Book Detail --> <h2 id="detail">Book Detail</h2> <p> GET <a href="/books/9781787125421" target="_blank">/books/:isbn</a> </p> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png" } </code> </pre> <!-- Book Create --> <h2 id="create">Book Create</h2> <p>POST <a href="/books" target="_blank">/books</a></p> <p>Include a <code>Content-Type: application/json</code> header to use the JSON in the request body. Otherwise it will return a 2XX status code, but without changes being made to the data.</p> <p>Title and ISBN are required fields.</p> <div class="row"> <div class="col-6"> <strong>Payload:</strong> <pre class="mb-4"> <code class="json"> { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png" } </code> </pre> </div> <div class="col-6"> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png" } </code> </pre> </div> </div> <strong>Error Response</strong> <p>400 Status Code</p> <pre class="mb-4"> <code class="json"> { "errors": { "isbn": { "msg": "Es muss eine ISBN angegeben werden.", "param": "isbn", "location": "body" }, "title": { "msg": "Es muss ein Titel angegeben werden.", "param": "title", "location": "body" } } } </code> </pre> <!-- Book Update --> <h2 id="update">Book Update</h2> <p> PUT <a href="/books/9781787125421" target="_blank">/books/:isbn</a> </p> <p>Include a <code>Content-Type: application/json</code> header to use the JSON in the request body. Otherwise it will return a 2XX status code, but without changes being made to the data.</p> <p>Title and ISBN are required fields.</p> <div class="row"> <div class="col-6"> <strong>Payload:</strong> <pre class="mb-4"> <code class="json"> { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png" } </code> </pre> </div> <div class="col-6"> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png" } </code> </pre> </div> </div> <strong>Error Response</strong> <p>400 Status Code</p> <pre class="mb-4"> <code class="json"> { "errors": { "isbn": { "msg": "Es muss eine ISBN angegeben werden.", "param": "isbn", "location": "body" }, "title": { "msg": "Es muss ein Titel angegeben werden.", "param": "title", "location": "body" } } } </code> </pre> <!-- Book Delete --> <h2 id="delete">Book Delete</h2> <p> DELETE <a href="/books/9781787125421" target="_blank">/books/:isbn</a> </p> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> Ok </code> </pre> <h2 id="operations">Operations</h2> <!-- Pagination --> <h2 id="pagination">Pagination</h2> <p>GET <a href="/books?_page=2&_limit=10" target="_blank">/books?_page=2&_limit=10</a></p> <p>Use <code>_page</code> and optionally <code>_limit</code> to paginate returned data. 10 items are returned by default</p> <p>In the <code>Link</code> header you'll get <code>first</code>, <code>prev</code>, <code>next</code> and <code>last</code> links.</p> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> [ { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png" }, … ] </code> </pre> <!-- Sort --> <h2 id="sort">Sort</h2> <p>GET <a href="/books?_sort=title&_order=desc" target="_blank">/books?_sort=title&_order=desc</a></p> <p>Add <code>_sort</code> and <sort>_order</sort> (ascending order by default)</p> <p>Use a comma-separated list for multiple fields.</p> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> [ { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png" }, … ] </code> </pre> <!-- Slice --> <h2 id="slice">Slice</h2> <p>GET <a href="/books?_start=10&_end=20" target="_blank">/books?_start=10&_end=20</a></p> <p>Add <code>_start</code> and <code>_end</code> or <code>_limit</code> (an <code>X-Total-Count</code> header is included in the response)</p> <p>Works exactly as <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice" target="_blank">Array.slice</a> (i.e. <code>_start</code> is inclusive and <code>_end</code> exclusive)</p> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> [ { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png" }, … ] </code> </pre> <!-- Operators --> <h2 id="operators">Operators</h2> <p>GET <a href="/books?numPages_gte=100&numPages_lte=500" target="_blank">/books?numPages_gte=100&numPages_lte=500</a></p> <p>Add <code>_gte</code> or <code>_lte</code> for getting a range</p> <p>Add <code>_ne</code> to exclude a value</p> <p>Add <code>_like</code> to filter (RegExp supported)</p> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> [ { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png" }, … ] </code> </pre> <!-- Full-text search --> <h2 id="search">Full-text search</h2> <p>GET <a href="/books?q=vue" target="_blank">/books?q=vue</a></p> <p>Add <code>q</code> for a full-text search</p> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> [ { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png" }, … ] </code> </pre> <h2 id="authentication">Authentication</h2> <!-- Register --> <h2 id="register">Register</h2> <p>POST <a href="/register" target="_blank">/register</a></p> <p>The response contains the JWT access token (expiration time of 1 hour). The access token has the following claims: <ul> <li><code>sub:</code> the user id.</li> <li><code>email:</code> the user email.</li> </ul> </p> <div class="row"> <div class="col-6"> <strong>Payload:</strong> <pre class="mb-4"> <code class="json"> { email: "youremail@demo.com", password: "bestPassw0rd", } </code> </pre> </div> <div class="col-6"> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> { accessToken: "xxx.xxx.xxx", user: { email: "email@domain.com", password: "HASH", id: 1 } } </code> </pre> </div> </div> <strong>Other propreties</strong> <p>Any other property can be added to the request body without being validated</p> <pre class="mb-4"> <code class="json"> { email: "youremail@demo.com", password: "bestPassw0rd", firstname: "Max", lastname: "Mustermann", age: 101 } </code> </pre> <!-- Login --> <h2 id="login">Login</h2> <p>POST <a href="/login" target="_blank">/login</a></p> <p>The response contains the JWT access token (expiration time of 1 hour). The access token has the following claims: <ul> <li><code>sub:</code> the user id.</li> <li><code>email:</code> the user email.</li> </ul> </p> <div class="row"> <div class="col-6"> <strong>Payload:</strong> <pre class="mb-4"> <code class="json"> { email: "youremail@demo.com", password: "bestPassw0rd", } </code> </pre> </div> <div class="col-6"> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> { accessToken: "xxx.xxx.xxx", user: { email: "email@domain.com", password: "HASH", id: 1 } } </code> </pre> </div> </div> <!-- User Update --> <h2 id="user_update">User Update</h2> <p>Any update to an existing user (via PATCH or PUT methods) will go through the same process for email and password.</p> <p>PUT <a href="/users/1" target="_blank">/users/:id</a> <br/> PATCH <a href="/users/1" target="_blank">/users/:id</a></p> <h2 id="user_default_login" class="mt-5">Admin User - Login Data</h2> <p>There is already a demo user inserted into the database. The credentials to login as this admin user are as follows: <ul> <li><code>admin@bookmonkey.api</code></li> <li><code>password1!</code></li> </ul> </p> <!-- Users --> <h2 id="users" class="mt-5">User Relation</h2> <p>A book can be linked to a specific user by sending the <code>userId</code> parameter when adding a book via <code>POST</code>.</p> <div class="row"> <div class="col-6"> <strong>Payload:</strong> <pre class="mb-4"> <code class="json"> { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png", userId: "1" } </code> </pre> </div> <div class="col-6"> <strong>Response:</strong> <pre class="mb-4"> <code class="json"> { title: "…", subtitle: "…", isbn: "…", abstract: "…", numPages: 123, author: "…", publisher: "…", price: "$..", cover: "http://….png", userId: "1" } </code> </pre> </div> </div> <h3>Relational Request</h3> <p>You can retrieve a book list for a specific user with the nested book route.</p> <p>PUT <a href="/users/1/books" target="_blank">/users/:id/books</a></p> <h2 id="guarded_routes" class="mt-5">Guarded Routes</h2> <div class="row"> <div class="col-12"> <p>Guarded routes exist at the root and can restrict access to any resource you put after them:</p> <table class="w-100"> <thead> <tr> <th width="30%">Route</th> <th width="70%">Resource permissions</th> </tr> </thead> <tbody> <tr> <td><code>/664/*</code></td> <td>User must be logged to <i>write</i> the resource. <br> Everyone can <i>read</i> the resource.</td> </tr> <tr> <td><code>/660/*</code></td> <td>User must be logged to <i>write</i> and <i>read</i> the resource.</td> </tr> <tr> <td><code>/644/*</code></td> <td>User must own the resource to <i>write</i> the resource. <br> Everyone can <i>read</i> the resource.</td> </tr> <tr> <td><code>/640/*</code></td> <td>User must own the resource to <i>write</i> the resource. <br> User must be logged to <i>read</i> the resource.</td> </tr> <tr> <td><code>/600/*</code></td> <td>User must own the resource to <i>write</i> or <i>read</i> the resource.</td> </tr> <tr> <td><code>/444/*</code></td> <td>No one can <i>write</i> the resource. <br> Everyone can <i>read</i> the resource.</td> </tr> <tr> <td><code>/440/*</code></td> <td>No one can <i>write</i> the resource. <br> User must be logged to <i>read</i> the resource.</td> </tr> <tr> <td><code>/400/*</code></td> <td>No one can <i>write</i> the resource. <br> User must own the resource to <i>read</i> the resource.</td> </tr> </tbody> </table> <h3 class="mt-2">Examples:</h3> <p>Public user (not logged-in) does the following requests:</p> <table class="w-100"> <thead> <tr> <th width="30%">Request</th> <th width="70%">Response</th> </tr> </thead> <tbody> <tr> <td><code>GET /664/books</code></td> <td><code>200 OK</code></td> </tr> <tr> <td><code>POST /664/books</code><br><code>{isbn: '123123123'}</code></td> <td><code>401 UNAUTHORIZED</code></td> </tr> </tbody> </table> <p class="mt-3">Logged-in user with <code>id: 1</code> does the following requests:</p> <table class="w-100"> <thead> <tr> <th width="30%">Request</th> <th width="70%">Response</th> </tr> </thead> <tbody> <tr> <td><code>GET /600/users/1</code><br><code>Authorization: Bearer xxx.xxx.xxx</code></td> <td><code>200 OK</code></td> </tr> <tr> <td><code>GET /600/users/42</code><br><code>Authorization: Bearer xxx.xxx.xxx</code></td> <td><code>403 FORBIDDEN</code></td> </tr> </tbody> </table> </div> </div> </main> </body> </html>