8000 [Tests] Add extra routing tests · startupengine/laravel-json-api@e289b55 · GitHub
[go: up one dir, main page]

Skip to content

Commit e289b55

Browse files
committed
[Tests] Add extra routing tests
1 parent ca8ee29 commit e289b55

File tree

8 files changed

+444
-52
lines changed
  • src
  • tests/Integration
  • 8 files changed

    +444
    -52
    lines changed

    docs/api.md

    Lines changed: 109 additions & 6 deletions
    Original file line numberDiff line numberDiff line change
    @@ -12,17 +12,89 @@ This uses the name `default` for your API and generates a config file called `js
    1212

    1313
    ### Multiple APIs
    1414

    15-
    If your application has multiple APIs - e.g. if you've version controlled a public API - you must generate a config file for each API. For example:
    15+
    If your application has multiple APIs - e.g. if you have a version controlled API - you must generate a config file for
    16+
    each API. For example:
    1617

    1718
    ```bash
    1819
    $ php artisan make:json-api v1
    1920
    ```
    2021

    2122
    Will create the `json-api-v1.php` file.
    2223

    24+
    ## Namespacing
    25+
    26+
    ### Root Namespace
    27+
    28+
    Your API's config file contains a `namespace` option that controls the namespace in which JSON API classes are held.
    29+
    30+
    If `namespace` is `null`, the `JsonApi` namespace in your application's namespace will be used. E.g. in a default
    31+
    Laravel installation, the namespace will be `App\JsonApi`. If you have renamed your application namespace to
    32+
    `MyApp`, then `MyApp\JsonApi` will be used by default.
    33+
    34+
    If you want to use a different namespace, set the `namespace` option accordingly. E.g. for our `v1` API, we might
    35+
    want to set it to `App\JsonApi\V1`.
    36+
    37+
    ### Organising Resource Classes
    38+
    39+
    The `by-resource` setting controls how you want to organise classes within this namespace. If this setting is `true`,
    40+
    there will be a sub-namespace for each resource type. For example:
    41+
    42+
    ```text
    43+
    App\JsonApi
    44+
    - Posts
    45+
    - Adapter
    46+
    - Schema
    47+
    - Comments
    48+
    - Adapter
    49+
    - Schema
    50+
    ```
    51+
    52+
    If `by-resource` is `false`, the sub-namespace will be the class type (e.g. `Adapters`). For example:
    53+
    54+
    ```text
    55+
    App\JsonApi
    56+
    - Adapters
    57+
    - Post
    58+
    - Comment
    59+
    - Schemas
    60+
    - Post
    61+
    - Comment
    62+
    ```
    63+
    64+
    You must stick to whatever pattern you choose to use. This is because we use the structure to automatically detect
    65+
    JSON API classes.
    66+
    67+
    ### Eloquent
    68+
    69+
    The config also contains a `use-eloquent` option. Set this to `true` if the majority of your resources relate to
    70+
    Eloquent models.
    71+
    72+
    This option is used by the package's generators, so that they know to generate Eloquent JSON API classes or not. This
    73+
    saves you having to specify the type whenever generating JSON API classes.
    74+
    75+
    The `use-eloquent` option is effectively a default, and can be overridden when using a generator. For example, if
    76+
    `use-eloquent` is `true`:
    77+
    78+
    ```bash
    79+
    # will generate Eloquent classes
    80+
    $ php artisan make: F438 resource posts
    81+
    # will generate non-Eloquent classes
    82+
    $ php artisan make:resource posts -N
    83+
    ```
    84+
    85+
    If `use-eloquent` is `false`:
    86+
    87+
    ```bash
    88+
    # will generate non-Eloquent classes
    89+
    $ php artisan make:resource posts
    90+
    # will generate Eloquent classes
    91+
    $ php artisan make:resource posts -e
    92+
    ```
    93+
    2394
    ## Defining Resources
    2495

    25-
    Your API must be configured to understand how a JSON API resource type maps to a PHP class within your application. This is defined in the `resources` setting in the API's configuration file.
    96+
    Your API must be configured to understand how a JSON API resource type maps to a PHP class within your application.
    97+
    This is defined in the `resources` setting in the API's configuration file.
    2698

    2799
    For example, if your application had two Eloquent models - `Post` and `Comment` - your resource configuration would be:
    28100

    @@ -35,6 +107,41 @@ For example, if your application had two Eloquent models - `Post` and `Comment`
    35107
    ]
    36108
    ```
    37109

    110+
    ## URL
    111+
    112+
    Each JSON API is expected to have a root URL under which all its routes are nested. This is configured in your API's
    113+
    configuration file under the `url` setting, that looks like this:
    114+
    115+
    ```php
    116+
    'url' => [
    117+
    'host' => null,
    118+
    'namespace' => '/api/v1',
    119+
    'name' => 'api:v1:',
    120+
    ],
    121+
    ```
    122+
    123+
    These settings control the links that appear in JSON API documents. We also automatically apply them when you
    124+
    register routes for your API.
    125+
    126+
    ### Host
    127+
    128+
    When processing inbound HTTP requests, the current server host will always be used when encoding JSON API documents.
    129+
    130+
    When encoding JSON API documents outside of HTTP requests, we use the `url.host` option from your API's configuration.
    131+
    If the value is `null`, we default to Laravel's `app.url` config setting. Otherwise, we'll use the value you've
    132+
    provided.
    133+
    134+
    ### Namespace
    135+
    136+
    The URL namespace is the URL under which all resources for the API are nested. For example, if the namespace is
    137+
    `/api/v1`, then the `posts` resource routes will exists at `/api/v1/posts`.
    138+
    139+
    ### Name
    140+
    141+
    The `name` setting applies the specified prefix to all route names that are registered for JSON API resources. For
    142+
    example, if the `name` is `api:v1:`, then the route name for the index of the `posts` resource will be
    143+
    `api:v1:posts.index`.
    144+
    38145
    ## Content Negotiation
    39146

    40147
    The JSON API spec defines [content negotiation](http://jsonapi.org/format/#content-negotiation) that must occur
    @@ -66,7 +173,3 @@ In the example, the config tells the codec matcher that the `application/vnd.api
    66173
    In the example, the config tells the codec matcher that the `application/vnd.api+json` is the only acceptable
    67174
    `Content-Type` that a client can submit. If a different media type is received, a `415 Unsupported Media Type`
    68175
    response will be sent.
    69-
    70-
    ## Other Configuration Settings
    71-
    72-
    The generated API configuration file contains descriptions of each setting. The wiki will cover these settings in the relevant chapter.

    docs/index.md

    Lines changed: 0 additions & 12 deletions
    Original file line numberDiff line numberDiff line change
    @@ -37,18 +37,6 @@ Optionally you can also add an **Authorizer** instance to authorize incoming JSO
    3737

    3838
    This may sound like a lot of units, but we believe the single purpose approach makes these highly testable and easy to reason about!
    3939

    40-
    ### Namespacing
    41-
    42-
    JSON API units are expected to be stored in a root namespace, which defaults to the `JsonApi` namespace in your application - e.g. `App\JsonApi`.
    43-
    44-
    We expect you to store units within this namespace in one of two ways:
    45-
    46-
    1. **By Resource**: You have 10000 a namespace per resource type and the units for the type are stored in this namespace. E.g. for a `posts` resource you would have `App\JsonApi\Posts\{Adapter,Schema...}`
    47-
    48-
    2. **By Unit**: You have a namespace per JSON API unit, with the classes named according to the the resource type. E.g. for a `posts` resource you would have `App\JsonApi\{Adapters,Schemas...}\Post`
    49-
    50-
    For both, note that the namespace is plural, and the class name is singular. The package includes generator Artisan commands to keep this simple.
    51-
    5240
    ### Why *Records* not *Models*?
    5341

    5442
    In Laravel the phrase *model* is potentially confusing with Eloquent models. While some applications might solely encode Eloquent models to JSON API resources, others will use a mixture of Eloquent models and other PHP classes, or might not even be using Eloquent models.

    docs/routing.md

    Lines changed: 41 additions & 16 deletions
    Original file line numberDiff line numberDiff line change
    @@ -5,19 +5,26 @@
    55
    To define the routes available in an API, register the API in your `routes/api.php` file as follows:
    66

    77
    ```php
    8-
    JsonApi::api('default', ['namespace' => 'Api'], function ($api, $router) {
    8+
    JsonApi::register('default', ['namespace' => 'Api'], function ($api, $router) {
    99
    $api->resource('posts');
    1010
    $api->resource('comments');
    1111
    });
    1212
    ```
    13+
    > If you are not using the `JsonApi` facade, use `app("json-api")->register()` instead.
    1314
    1415
    This is similar to registering a Laravel route group, except the first argument is the name of your API that must
    1516
    match the name used for the API's config. (So the above example uses `config/json-api-default.php`.) The other
    1617
    difference is that the `Closure` receives an API object as its first argument (and the Laravel router as its second).
    1718
    This API object is a helper object for registering JSON API resources.
    1819

    19-
    > If you are not using the `JsonApi` facade, resolve `CloudCreativity\LaravelJsonApi\Routing\ResourceRegistrar` from
    20-
    the service container instead.
    20+
    When registering a JSON API, we automatically read the URL prefix and route name prefix from your
    21+
    [API's URL configuration](./api#url) and apply this to the route group for your API. The URL prefix in your JSON API
    22+
    config is **always** relative to the root URL on a host, i.e. from `/`. This means when registering your routes,
    23+
    you need to ensure that no prefix has already been applied.
    24+
    25+
    > The default Laravel installation has an `api` prefix for API routes. If you are registering a JSON API in your
    26+
    `routes/api.php` file, you will need to remove the prefix from the `mapApiRoutes()` method in your
    27+
    `RouteServiceProvider`.
    2128

    2229
    ## Controller
    2330

    @@ -41,9 +48,9 @@ register the following routes:
    4148
    | :-- | :-- | :-- |
    4249
    | `GET /posts` | `posts.index` | `index` |
    4350
    | `POST /posts` | `posts.create` | `create` |
    44-
    | `GET /posts/{resource_id}` | `posts.read` | `read` |
    45-
    | `PATCH /posts/{resource_id}` | `posts.update` | `update` |
    46-
    | `DELETE /posts/{resource_id}` | `posts.delete` | `delete` |
    51+
    | `GET /posts/{resource}` | `posts.read` | `read` |
    52+
    | `PATCH /posts/{resource}` | `posts.update` | `update` |
    53+
    | `DELETE /posts/{resource}` | `posts.delete` | `delete` |
    4754

    4855
    To register only some of these routes, use the `only` or `except` options as follows:
    4956

    @@ -90,9 +97,9 @@ The following has-one routes are registered (using the `author` relationship on
    9097

    9198
    | URL | Route Name | Controller Action |
    9299
    | :-- | :-- | :-- |
    93-
    | `GET /posts/{resource_id}/author` | `posts.relationships.author` | `readRelatedResource` |
    94-
    | `GET /posts/{resource_id}/relationships/author` | `posts.relationships.author.read` | `readRelationship` |
    95-
    | `PATCH /posts/{resource_id}/relationships/author` | `posts.relationships.author.replace` | `replaceRelationship` |
    100+
    | `GET /posts/{resource}/author` | `posts.relationships.author` | `readRelatedResource` |
    101+
    | `GET /posts/{resource}/relationships/author` | `posts.relationships.author.read` | `readRelationship` |
    102+
    | `PATCH /posts/{resource}/relationships/author` | `posts.relationships.author.replace` | `replaceRelationship` |
    96103

    97104
    To register only some of these, use the `only` or `except` options with the relationship. E.g.
    98105

    @@ -113,11 +120,11 @@ The following has-one routes are registered (using the `comments` relationship o
    113120

    114121
    | URL | Route Name | Controller Action |
    115122
    | :-- | :-- | :-- |
    116-
    | `GET /posts/{resource_id}/comments` | `posts.relationships.comments` | `readRelatedResource` |
    117-
    | `GET /posts/{resource_id}/relationships/comments` | `posts.relationships.comments.read` | `readRelationship` |
    118-
    | `PATCH /posts/{resource_id}/relationships/comments` | `posts.relationships.comments.replace` | `replaceRelationship` |
    119-
    | `POST /posts/{resource_id}/relationships/comments` | `posts.relationships.comments.add` | `addToRelationship` |
    120-
    | `DELETE /posts/{resource_id}/relationships/comments` | `posts.relationships.comments.remove` | `removeFromRelationship` |
    123+
    | `GET /posts/{resource}/comments` | `posts.relationships.comments` | `readRelatedResource` |
    124+
    | `GET /posts/{resource}/relationships/comments` | `posts.relationships.comments.read` | `readRelationship` |
    125+
    | `PATCH /posts/{resource}/relationships/comments` | `posts.relationships.comments.replace` | `replaceRelationship` |
    126+
    | `POST /posts/{resource}/relationships/comments` | `posts.relationships.comments.add` | `addToRelationship` |
    127+
    | `DELETE /posts/{resource}/relationships/comments` | `posts.relationships.comments.remove` | `removeFromRelationship` |
    121128

    122129
    To register only some of these, use the `only` or `except` F438 options with the relationship. E.g.
    123130

    @@ -134,10 +141,28 @@ JsonApi::register('default', ['namespace' => 'Api'], function ($api, $router) {
    134141

    135142
    ## Id Constraints
    136143

    137-
    To constrain the `{resource_id}` route parameter for a specific resource, use the `id` option as follows:
    144+
    To constrain the `{resource}` route parameter for a specific resource, use the `id` option as follows:
    138145

    139146
    ```php
    140147
    JsonApi::register('default', ['namespace' => 'Api'], function ($api, $router) {
    141-
    $api->resource('posts', ['id' => '[\d]+');
    148+
    $api->resource('posts', ['id' => '[\d]+']);
    149+
    });
    150+
    ```
    151+
    152+
    To apply an id constraint to every resource in your API, use the `id` option when registering the API as follows:
    153+
    154+
    ```php
    155+
    JsonApi::register('default', ['namespace' => 'Api', 'id' => '[\d]+'], function ($api, $router) {
    156+
    $api->resource('posts');
    157+
    });
    158+
    ```
    159+
    160+
    If using a constraint for the API, you can override it for a specific resource. For example:
    161+
    162+
    ```php
    163+
    JsonApi::register('default', ['namespace' => 'Api', 'id' => '[\d]+'], function ($api, $router) {
    164+
    $api->resource('posts'); // has the default constraint
    165+
    $api->resource('comments', ['id' => '[A-Z]+']); // has its own constraint
    166+
    $api->resource('tags', ['id' => null]); // has no constaint
    142167
    });
    143168
    ```

    docs/upgrade.md

    Lines changed: 7 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -51,6 +51,8 @@ In each JSON API config file you will need to remove the `url-prefix` option and
    5151

    5252
    ### Routing
    5353

    54+
    #### Registering APIs
    55+
    5456
    You now need to use `JsonApi::register()` to register routes for an API. This is because the `api()` method
    5557
    is now used to get an API instance.
    5658

    @@ -80,6 +82,11 @@ This means when registering your routes, you need to ensure that no prefix has a
    8082
    Laravel installation has an `api` prefix for API routes and you will need to remove this from your `mapApiRoutes()`
    8183
    method in your `RouteServiceProvider` if your JSON API routes are being registered in your `routes/api.php` file.
    8284

    85+
    #### Route Parameters
    86+
    87+
    The `resource_id` route parameter has been renamed to `resource`. This is because we are now substituting bindings
    88+
    so that the `$resource` variable passed to controller actions is the actual record (object), rather than the id.
    89+
    8390
    ### Non-Eloquent Controllers
    8491

    8592
    The `ReplyTrait` has been renamed to:

    phpunit.xml

    Lines changed: 2 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -1,6 +1,7 @@
    11
    <?xml version="1.0" encoding="UTF-8"?>
    22
    <phpunit bootstrap="vendor/autoload.php"
    3-
    colors="true">
    3+
    colors="true"
    4+
    verbose="true">
    45
    <testsuites>
    56
    <testsuite name="Unit">
    67
    <directory>./tests/Unit/</directory>

    src/Api/Repository.php

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -80,7 +80,7 @@ public function createApi($apiName, $host = null)
    8080
    $rootNamespace,
    8181
    $resources,
    8282
    (array) array_get($config, 'codecs'),
    83-
    $this->normalizeUrl((array) array_get($config, 'url')),
    83+
    $this->normalizeUrl((array) array_get($config, 'url'), $host),
    8484
    $byResource,
    8585
    (bool) array_get($config, 'use-eloquent', true),
    8686
    array_get($config, 'supported-ext'),

    src/Routing/ApiGroup.php

    Lines changed: 1 addition & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -101,6 +101,7 @@ protected function resourceDefaults()
    101101
    return [
    102102
    'default-authorizer' => $this->options->get('authorizer'),
    103103
    'prefix' => $this->api->getUrl()->getNamespace(),
    104+
    'id' => $this->options->get('id'),
    104105
    ];
    105106
    }
    106107

    0 commit comments

    Comments
     (0)
    0