Problem/Motivation

There is no human readable documentation for a REST API.

Proposed resolution

Provide documentation for link relations. For example, see http://haltalk.herokuapp.com/rels/posts. When a site enables HAL, this documentation can be used to guide users through the API... see HAL Browser for HAL Talk.

Some APIs to XREF our new one.

How to test

  1. http://drupal.d8/admin/help/rest follow link to API
  2. http://drupal.d8/docs/rest/api
  3. http://drupal.d8/docs/rest/api/types/node/article
  4. http://drupal.d8/rest/relation/node/article/title

Remaining tasks

Code TODOs

ResourceRoutes.php
(103, 6) * TODO: why do we generate routes for relations?
(110, 8) // TODO: why filter out the non relation ones? Ie field_image is exposed through _links to ie HAL browser.
(119, 12) // FIXME
(122, 16) // TODO why use relation in link. This should be in */api/* path
(165, 8) // TODO: Change this to only expose info for REST enabled entity types.
(166, 8) // TODO: filter out all ConfigEntities

Controller.php
(15, 6) // TODO use DiC
(124, 8) // TODO fix for drupal_set_title
(133, 8) // TODO: SA what information is disclosed?
(135, 8) // TODO: how to check for field permissions?
(157, 8) // TODO use DIC
(162, 8) // TODO: Change this to only expose info for REST enabled entity types.
(169, 8) // TODO use DIC

User interface changes

API changes

Original report by @linclark

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Anonymous’s picture

Status: Active » Needs review
Issue tags: +WSCCI
FileSize
6.29 KB

Just to get the conversation about this rolling, I put together a simple implementation which only exposes documentation for entity_reference fields. To see it in action, enable entity_test and go to relations/user_id.

I was basing this on the HAL Talk example, which includes optional and required fields which will be displayed. As I was doing this, I realized that we don't know which fields are available, since there may be some on the bundle. Entity reference field only restricts entity type.

Status: Needs review » Needs work

The last submitted patch, 1925618-rest-docs.patch, failed testing.

Anonymous’s picture

It turns out that entity reference instances can be restricted to particular bundles. So... do we have link relations that are by the bundle? For example, site:entity_test/entity_test/user_id?

Crell’s picture

Status: Needs work » Needs review
+++ b/core/modules/rest/lib/Drupal/rest/EventSubscriber/RouteSubscriber.php
@@ -62,7 +64,40 @@ public function dynamicRoutes(RouteBuildEvent $event) {
+              '_access' => 'TRUE',

We probably don't want to make this API blanket-open. A fairly loose permission, perhaps, but I don't think we want it globally accessible, period. By design it is an insight into the data model of the site, which MAY pose an information exposure risk. We should at least allow people the opportunity to lock that down.

I think just tossing an "Access REST/HAL API documentation" permission on it should be sufficient; people can then decide how liberal to be with that permission.

+++ b/core/modules/rest/lib/Drupal/rest/EventSubscriber/RouteSubscriber.php
@@ -72,7 +107,10 @@ public function dynamicRoutes(RouteBuildEvent $event) {
   static function getSubscribedEvents() {
-    $events[RoutingEvents::DYNAMIC] = 'dynamicRoutes';
+    $events[RoutingEvents::DYNAMIC] = array(
+      array('resourceRoutes'),
+      array('relationRoutes'),
+    );
     return $events;

Minor nit, for most getSubscribedEvents() implementations we've been doing

$events[$event_name][] = array('nameOfMethod', $priority);
$events[$event_name][] = array('nameOfOtherMethod', $priority);

And making it multiple lines. That makes it easier to read/edit than nesting the array definitions.

Do we want to also provide information on fields, or is that something that we will add later?

Anonymous’s picture

We probably don't want to make this API blanket-open... I think just tossing an "Access REST/HAL API documentation" permission on it should be sufficient

Agreed, I only set it to open access temporarily. I would just say "Access REST documentation" since I think this documentation may eventually include things that apply to application/json.

Do we want to also provide information on fields, or is that something that we will add later?

This is part of the problem... if we provide information on fields, we need to know the possible bundles, not just the target entity type. This means that we have to coin a new relation for each instance, not just each field.

If we decide we do want to go this way, then I would suggest that in the Body part of the link relation docs, we simply link to the possible types, eg http://ex.com/node/article. That URI would provide documentation of the required and optional properties. Based on some opinions I've read, this use of typing (where multiple types can be posted to the same URI, but there are restrictions based on link relation) might mean that our API is less RESTful since there is some out-of-band knowledge required. However, I don't see a practical way around it.

Handling the types with URIs gives us another benefit here. We can actually express this type information outside of the body itself using a Link relation header. This means that REST module could access it directly and determine which bundle it is expecting before passing the data off to the serialization system, which addresses some of Klaus's concerns from a few months ago.

Anonymous’s picture

I moved permissioning out to its own issue, #1926168: Add permissions for REST module's documentation, just in case anyone has any further considerations around that.

Anonymous’s picture

FileSize
4.27 KB
7.88 KB

This just adds a page for the type and changes the link relation to be per-instance instead of per-field.

Status: Needs review » Needs work

The last submitted patch, 1925618-07-rest-docs.patch, failed testing.

moshe weitzman’s picture

Perhaps related - Nice Wordpress REST docs at http://developer.wordpress.com/docs/api/.

vivekvpandya’s picture

Issue summary: View changes

This is not a documentation but it may help
POST, PATCH and DELETE request with Drupal 8 REST services

clemens.tolboom’s picture

We tried to move the code in place but failed with lot's of issues.

clemens.tolboom’s picture

  1. diff --git a/.htaccess b/.htaccess
    

    Does not belong to patch

  2. +++ b/core/modules/rest/src/Routing/ResourceRoutes.php
    @@ -97,4 +97,66 @@ protected function alterRoutes(RouteCollection $collection) {
    +  public function relationRoutes(RouteBuildEvent $event) {
    

    Should this belong to RoutingEvents ?

  3. +++ b/core/modules/rest/src/Routing/ResourceRoutes.php
    @@ -97,4 +97,66 @@ protected function alterRoutes(RouteCollection $collection) {
    +  public function typeRoutes(RouteBuildEvent $event) {
    

    Should this belong to RoutingEvents ?

  4. +++ b/core/modules/rest/src/Routing/ResourceRoutes.php
    @@ -97,4 +97,66 @@ protected function alterRoutes(RouteCollection $collection) {
    diff --git a/core/modules/rest/src/de-patch.patch b/core/modules/rest/src/de-patch.patch
    

    Should this belong to RoutingEvents ?

  5. +++ b/core/modules/rest/templates/rest-documentation-section.html.twig
    @@ -0,0 +1,7 @@
    +        {{ render(headers) }}
    

    What happened to render()

clemens.tolboom’s picture

Issue summary: View changes
Status: Needs work » Needs review
FileSize
10.86 KB

I need review from a user and testbot.

clemens.tolboom’s picture

One of the TODOs is related #2300677: JSON:API POST/PATCH support for fully validatable config entities

Requesting http://drupal.d8/rest/types/image_style/image_style gives

PHP Fatal error:  Call to undefined method Drupal\\image\\Entity\\ImageStyle::getProperties() in /Users/clemens/Sites/drupal/d8/www/core/modules/rest/src/Controller.php on line 49

Status: Needs review » Needs work

The last submitted patch, 13: add_documentation_for-1925618-13.patch, failed testing.

clemens.tolboom’s picture

Status: Needs work » Needs review
FileSize
11.37 KB

Attached patch

Make relationRoutes work a little.
Remove duplicate routes generator.
Have a relation response part 1.
Fix for checkplain.

Current relations are

block_content:basic:type : entity_reference
node:article:type : entity_reference
node:article:uid : entity_reference
node:article:revision_uid : entity_reference
node:article:field_tags : taxonomy_term_reference
node:page:type : entity_reference
node:page:uid : entity_reference
node:page:revision_uid : entity_reference
file:file:uid : entity_reference
shortcut:shortcut:shortcut_set : entity_reference

We still have no list page to get one started.

Status: Needs review » Needs work

The last submitted patch, 16: add_documentation_for-1925618-16.patch, failed testing.

Crell’s picture

clemens.tolboom’s picture

Issue summary: View changes

@Crell thanks for the XREFs

I've updated the summary regarding overview page / use ContentEntityType

clemens.tolboom’s picture

Assigned: Unassigned » clemens.tolboom
clemens.tolboom’s picture

Issue summary: View changes
Status: Needs work » Needs review
FileSize
11.07 KB

Attached patch fixed some TODOs and added a few.

Fixed TODOs

Controller.php
(35, 11) // TODO Add required and optional fields here.
(42, 8) // TODO: fix for CR https://www.drupal.org/node/2067859
(72, 8) // TODO : make this a proper content response somehow.

ResourceRoutes.php
(124, 8) // TODO: Missing bundle for entity type contact_message
(193, 8) // TODO fix method resourceRoutes
(195, 8) // TODO fix relationRoutes

Remaining TODOs:

ResourceRoutes.php
(110, 6) * TODO: why do we generate routes for relations?
(170, 8) // TODO: Change this to only expose info for REST enabled entity types.
(171, 8) // TODO: filter out all ConfigEntities

Controller.php
(16, 8) // TODO fix for drupal_set_title
(33, 11) // @todo Add required and optional fields here.
(40, 8) // TODO: fix for CR https://www.drupal.org/node/2067859
(48, 8) // TODO: how to present the information?
(50, 8) // TODO: SA what information is disclosed?
(52, 8) // TODO: how to check for field permissions?
(64, 10) // TODO: setting may contain array as value

Considerations:

- What to expose to whom?
- Do we need an API version? Currently moved routes into /api
- Navigation around and into the API. How to discover the API?

clemens.tolboom’s picture

Issue summary: View changes
FileSize
12.03 KB

The chosen and dictated path do not match. Where should the Rest API documentation land? Our idea is under:

  1. /api/rest (list of resources)
  2. /api/rest/entity_type (list of bundle)
  3. /api/rest/entity_type/bundle (list of fields)
  4. /api/rest/entity_type/bundle/field_name (list of field properties)

Using https://github.com/mikekelly/hal-browser the documentation relation fields documentation work aka http://drupal.d8/rest/relation/node/article/uid ... we still don't get that links 'relation' part.

Documentation for _embed using hal-browser are properly mapped aka http://drupal.d8/rest/relation/node/article/field_image

- update all todos

larowlan’s picture

Clemens pointed me at this issue which I was unaware of.
Earlier in the week I knocked out drupal.org/project/rest_api_doc which seems to have similar goals to what's going on here, although not specifically around format of hal/embedded items.
Happy to pool efforts.

clemens.tolboom’s picture

Issue summary: View changes

Adding to more examples of nice APIs

https://dev.twitter.com/docs/api/1.1
https://developers.facebook.com/docs/graph-api/reference/v2.0

Note they have a version number into their API!

clemens.tolboom’s picture

dawehner’s picture

In general it feels a bit like this should be an additional module kind of.
As written on http://www.django-rest-framework.org/topics/documenting-your-api
there are various different ways of how API documentation can be done, depending on different usecases.

  1. +++ b/core/modules/rest/rest.module
    @@ -40,6 +41,37 @@ function rest_help($route_name, RouteMatchInterface $route_match) {
    +function template_preprocess_rest_documentation($variables) {
    +  $variables['field_description'] = String::checkPlain($variables['field_description']);
    +}
    

    With twig auto-escape you really don't need this anymore.

  2. +++ b/core/modules/rest/src/Controller.php
    @@ -0,0 +1,173 @@
    +class Controller extends ContainerAware {
    

    Please, don't make it ocntainer aware. This should also exist under the controller directory

clemens.tolboom’s picture

Assigned: clemens.tolboom » Unassigned

I'm not sure this should be in core either as it might block a beta release.

While trying to move this forward I had a lot of discussions and saw a lot APIs but found no documentation whatsoever so I liked the idea to have core self reflect on its documentation.

As Hal, Rest and Serializer need more attention I unassigned myself for now. Let's see what others think.

Crell’s picture

Status: Needs review » Postponed

IMO we shouldn't build any manual documentation at this point. Let's get #2113345: Define a mechanism for custom link relationships in (not beta blocking) and then we can dynamically build link documentation off of that in whatever form is needed.

Crell’s picture

Status: Postponed » Closed (duplicate)

This seems a duplicate of #2047283: Improve documentation for EntityType::$links at this point, da? Reopen if not.

clemens.tolboom’s picture

Status: Closed (duplicate) » Needs work

This patch produce something to browse to. #2047283: Improve documentation for EntityType::$links is static documentation. reopening.

IMHO REST is of few use when implementors have no API to browse through. This issue was a nice starting point. But it needs lots of work.

Crell’s picture

Version: 8.0.x-dev » 8.1.x-dev

My thinking is that all of this is for 8.1 at this point. However, for 8.1 we want to do this: #2113345: Define a mechanism for custom link relationships, which in turn will allow us to dynamically generate link documentation in whatever format we want. Thus a manual approach is unnecessary, as it won't get into 8.0 anyway and for 8.1 it won't be necessary. Hence won't-fix/duplicate.

clemens.tolboom’s picture

This issue is not a manual approach. It generate(d) all rest exposed entities fields and relations. Maybe I miss the relation with #2113345: Define a mechanism for custom link relationships.

@Crell please check patch from #22 then feel free to close if you think I'm wrong.

Wim Leers’s picture

Category: Task » Feature request
Issue tags: +API-First Initiative

This would be hugely helpful in improving the REST Experience.

johnhanley’s picture

I apologize for unearthing this old issue, but I'm struggling with using relations with REST in Drupal 8.

I have a custom ECK entity with node and user reference fields. I am able to successfully create an entity via POST, but the reference fields are empty.

Here's my JSON:

{
  "_links":{
    "type":{
      "href":"http://d8/rest/type/score/points"
    },
    "http://d8/rest/relation/node/game/entity_id":[
      {
        "href":"http://d8/node/2?_format=hal_json"
      }
    ],
    "http://d8/rest/relation/user/user/entity_id":[
      {
        "href":"http://d8/user/1?_format=hal_json"
      }
    ]
  },
  "_embedded":{
    "http://d8/rest/relation/node/game/entity_id":[
      {
        "_links":{
          "self":{
            "http://d8/node/2?_format=hal_json"
          },
          "type":{
            "http://d8/rest/type/node/game"
          }
        }
      }
    ],
    "http://d8/rest/relation/user/user/entity_id":[
      {
        "_links":{
          "self":{
            "http://d8/user/1?_format=hal_json"
          },
          "type":{
            "href":"http://d8/rest/type/user/user"
          }
        }
      }
    ]
  },
  "title":[
    {
      "value": "Score"
    }
  ],
  "field_points":[
    {
      "value": "100"
    }
  ]
}

Perhaps I need some fundamental questions answered before continuing.

1) Is there a way to programmatically generate the above JSON? I constructed it manually (with the help of REST API Documentation) and tested it with Postman, but is there an easier more efficient way?

2) When compared with another JSON examples found in other threads, the "_embedded" segments include a UUID. How does one go about generating a UUID in Drupal 8?

Given the sparse documentation currently available I suspect others will find the answers useful.

johnhanley’s picture

Following up on my previous post.

I discovered the UUID is stored with the entity. In my case the node and user tables. (I know the UUID can be retrieved with code, but I'm anxious to get this working and copied the value directly via MyAdmin.)

So armed with the respective UUID's, I have modified my JSON:

{
  "_links": {
    "type": {
      "href":"http://d8/rest/type/score/points"
    },
    "http://d8/rest/relation/node/game/entity_id":[
      {
        "href":"http://d8/node/2?_format=hal_json"
      }
    ],
    "http://d8/rest/relation/user/user/entity_id":[
      {
        "href":"http://d8/user/1?_format=hal_json"
      }
    ]
  },
  "_embedded":{
    "http://d8/rest/relation/node/game/entity_id":[
      {
        "_links":{
          "self":{
            "href":"http://d8/node/2?_format=hal_json"
          },
          "type":{
            "href":"http://d8/rest/type/node/game"
          }
        },
        "uuid":[
          {
            "value":"7e3ef711-42c0-4c60-8d06-6f6f997f02bd"
          }
        ]
      }
    ],
    "http://d8/rest/relation/user/user/entity_id":[
      {
        "_links":{
          "self":{
            "href":"http://d8/user/1?_format=hal_json"
          },
          "type":{
            "href":"http://d8/rest/type/user/user"
          }
        },
        "uuid":[
          {
            "value":"d3cd7111-d755-4690-b943-673f8a2036c4"
          }
        ]
      }
    ]
  },
  "title": [
    {
      "value": "Score"
    }
  ],
   "field_points":[
    {
      "value": "100"
    }
  ]
}

While this returns a 201 and creates the entity like before, the reference fields are still empty.

I will continue to toil away, but in the meantime any insight from someone in-the-know is greatly appreciated. :-)

jhodgdon’s picture

Please do not use Drupal Core issues (especially existing issues that were discussing something kind of related) in order to ask questions and get programming support. This is not the right forum.

There are several support options listed if you click on "Support" at the top of Drupal.org, which will take you to:
http://drupal.org/support

There you can find out about the Drupal IRC channels, and the Forums, which are our two main support mechanisms in the Drupal community. You might also try http://drupal.stackexchange.com/

Good luck with your issue!

johnhanley’s picture

I have resolved my issue. I am now able to successfully POST a custom entity with the field relations properly defined. Apologies.

jhodgdon’s picture

Sorry! No offence was meant. If you would like to contribute a patch for this issue, that would be most welcome!

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.0-beta1 was released on March 2, 2016, which means new developments and disruptive changes should now be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

clemens.tolboom’s picture

In #2237231: Support OPTIONS request we discovered GET + POST are allowed formats on most path even if not available for REST formats so we need to check against this when building this API.

Wim Leers’s picture

#34: No need to apologize! This is not at all an old issue :) But it is completely off-topic.

  1. Yes, look at the tests. E.g. \Drupal\rest\Tests\CreateTest. Also see https://www.drupal.org/documentation/modules/rest/post.
  2. Those other threads must be GETting or PATCHing, because when POSTing, already having a UUID does not make sense.

#35: There are other issues wrt entity reference fields.

#37: Oh, great to hear it's solved.

mpp’s picture

1. Hi @wim-leers, @jhodgdon could you explain in what way #34 off-topic is?

Some of the REST operations are documented on https://www.drupal.org/documentation/modules/rest but how to create embedded entities using "_embedded" in one REST POST is unfortunately not yet documented.

2. @bacteriaman, could you please share your solution in the documentation (https://www.drupal.org/documentation/modules/rest/post)? I'm looking for a way to create an article with tags in a single REST POST. The documented approach (doing a GET first and then sending the same JSON in a post) doesn't work (as the result of the GET only contains a uuid, not the term name, description etc).

3. Most services provide documentation on the interface itself. Take this wsdl for example: http://www.webservicex.com/globalweather.asmx?wsdl
If you navigate to the service endpoint, you get documentation about the interface: http://www.webservicex.com/globalweather.asmx
Not only can you get a sample request and response but you even get a working form to invoke the service operations.

4. The patch in 22 contains an error, _content should become _controller and path is ideally quoted:
+ path: '/docs/rest/api'
+ defaults:
+ _controller: 'Drupal\rest\Controller::docRoot'
Also ContainerAware is deprecated and instead of directly calling l('') and t(''), it 'd probably be cleaner to use LinkGeneratorTrait and StringTranslationTrait.

I'd be happy to help further but I need to figure out how it's working first which is really hard without the proper documentation.

Wim Leers’s picture

how to create embedded entities using "_embedded" in one REST POST is unfortunately not yet documented.

That's HAL+JSON territory, not REST territory. See https://www.drupal.org/documentation/modules/hal. Sadly, there is no maintainer for that module.

I need to figure out how it's working first which is really hard without the proper documentation.

I hear you! The documentation for REST is was very poor (hence I did http://wimleers.com/blog/restless-week), and the documentation for HAL is absolutely abysmal.

mpp’s picture

Thanks for the feedback Wim.

PS: note that the use of String class (in template_preprocess_rest_documentation()) won't be possible as it's a reserved word in php7 (See https://www.drupal.org/node/2454447).

mpp’s picture

clemens.tolboom’s picture

Status: Needs work » Needs review

@mmp any chance for a inter-diff-1925618-22-45?

The last submitted patch, 11: add_documentation_for-1925618-11.patch, failed testing.

The last submitted patch, 42: add_documentation_for-1925618-42.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 45: add_documentation_for-1925618-45.patch, failed testing.

mpp’s picture

diff add_documentation_for-1925618-42.patch add_documentation_for-1925618-45.patch
9c9
< +use Drupal\Component\Utility\String;
---
> +use Drupal\Component\Utility\SafeMarkup;
49c49
< + $variables['field_description'] = String::checkPlain($variables['field_description']);
---
> + $variables['field_description'] = SafeMarkup::checkPlain($variables['field_description']);

This is needed to prevent the following error in php7: Fatal error: Cannot use Drupal\Component\Utility\String as String because 'String' is a special class name

clemens.tolboom’s picture

@mpp thanks for the diff. On which version you wrote your patch as the test bot is unable to apply?

andypost’s picture

There's a lot of wrong usages of t(), most of them in controller should be $this->t()

+++ b/core/modules/rest/rest.module
@@ -40,6 +41,37 @@ function rest_help($route_name, RouteMatchInterface $route_match) {
+      $output .= '<h3>' . t('API Docs') . '</h3>';
+      $output .= '<p>' . t('The API documentation is viewable on') . ' <a href="/docs/rest/api">/docs/rest/api</a></p>';

should be proper link

Wim Leers’s picture

Title: Add documentation for REST link relations » Add rest_api_doc to Drupal core as an experimental module

I wonder if it would not be better to just add https://www.drupal.org/project/rest_api_doc to Drupal core as an experimental module?

klausi’s picture

I would let it mature in contrib, since core development tends to be slow. We can still link to it from all documentation pages. Once it has stabilized and has a stable release we could move it to core.

Wim Leers’s picture

+1. But the patch in this issue is just reimplementing everything in that contrib module. That's just a waste of time.

Also,melts not forget this would help make core's REST more approachable.

johnhanley’s picture

@mpp, I'm not ignoring your documentation request in #42. But before doing so I need to solve my CORS cross-domain configuration dilemma. Once armed with this information I will be able to more accurately describe how everything works from end-to-end.

John

mpp’s picture

@bacteriaman, no pressure ;-) good luck with the CORS issue.

@Wim, great idea! Adding rest_api_doc to core would be valuable or at least put in a link to that module somewhere in core (e.g. module description/help).

@clemens.tolboom, don't remember I've deleted it, let me know if I should re-roll. But I guess Wim is right, powers should be combined.

Grayside’s picture

I like the rest_api_doc module, but the industry practice and greater functionality of generating an Open API Specification (Swagger) schema would be better, and help connect Drupal rest to all the tooling for documentation, testing, code generation, and so on around that ecosystem.

Wim Leers’s picture

@Grayside: That sounds even better indeed.

dawehner’s picture

One issue jsonapi solves by splitting things into one resource per bundle is the documentability of the schema. For swagger for example (and the problem exists in rest_api_docs as well), you could just document the base fields, but not each individual configureable one.

Wim Leers’s picture

Title: Add rest_api_doc to Drupal core as an experimental module » Ensure Drupal's web services are self-documenting: Swagger support OR rest_api_doc to Drupal core as an experimental module?

Right.

Improving title to indicate that the direction is not at all certain yet.

Wim Leers’s picture

Status: Needs work » Active
kalinchernev’s picture

It's true that the direction of the issue is not very clear yet.
Reading through the thread:

Provide documentation for link relations

This is a small part of the information which an API documentation provides. As given the several examples, a documentation can be very descriptive (as the WordPress one) or more functional like Khan Academy's one for example. The latter seems to be generated out of apiDoc. Which in turn shows IMO the different aims an API documentation can have: "reading" vs "trying" modes. apiDoc and Swagger are examples of such which provide "trying" experience together with the reading part.
So, I think one of the important questions here is: what type of documentation should be generated aiming to serve what purpose?
Where should the documentation be displayed? For example, it could be a Drupal page, but if Swagger definition is used, then a swagger-ui page can be generated, either as an embedded resource in Drupal or totally separate page in a SPA in case of fully decoupled, i.e. swagger specification is more inter-operable, for example.

Checkout https://www.drupal.org/project/services_docs to see what can be used esp. UX parts if any.

The code here is for Drupal 7 and still containing debugging statements. Could be taken out of the todo IMO.

Should we introduce an API version? Do we need an API version? Currently moved routes into /api

It's a good practice to support versioning, for sure.

What to expose to whom? Should there be a 'Read API' permission? How to handle field permissions?

I removed this one, and added a reference to #1926168: Add permissions for REST module's documentation because of #6

#2773007: Support Swagger is referenced from this issue, but here Swagger is only mentioned pretty late in the discussion after some work done. Maybe it will be useful to have a clear idea whether this is going to be an acceptable format or not before going too far working on self-documentation as there are tools to help with that already. Namely, there are swagger integrations for PHP but also keep in mind that yml is very close to the main toolchain already, i.e. http://editor.swagger.io is what many non-developers use to make specifications for developers.

In summary, there are several questions to be clarified, with main points being:

  • Parsing: where to take information from, i.e. code, configurations, yml, etc.
  • Formats: Drupal-custom, apiDoc, swagger, API blueprint, etc
  • Visualization: Drupal-custom, swagger UI, mixture, etc.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Grayside’s picture

#2773007: Support Swagger is in a recent contrib module of mine, where Swagger is a roadmap goal.

Parsing: where to take information from, i.e. code, configurations, yml, etc.

API Design documentation needs to balance depth of information to match the developer audience with a strategy to ensure documentation is always accurate and up-to-date. Drupal Core's REST APIs automatically derive from the system configuration, there is no reason not to use the configuration to drive the documentation.

(This is a more complex question if you scope-in payload customization, architecturally driven versioning, and so on.)

Formats: Drupal-custom, apiDoc, swagger, API blueprint, etc

APIs are about interoperability. It would be inconsistent and self-limiting if Drupal as an API framework concentrated on non-interoperable documentation. Especially given the number of API meta-services (API Management platforms, documentation & support systems, code generation tools, etc) that can be driven by machined descriptions. However, API documentation is critical for any API's MVP.

Visualization: Drupal-custom, swagger UI, mixture, etc.

This might matter if the visualization options are a key determinant of the format to use. Swagger is the front-runner standing for developer documentation of existing systems and not tied to a specific company's services.

Swagger UI and API documentation services that can read swagger descriptions do a decent job of producing documentation, but if you want the documentation to be a careful match for the Drupal site, a custom UI seems necessary. Not sure what may have changed in the last year, but Swagger UI as a library is more of an embeddable application. You can fork it to make changes, but it's not easy to adapt.

Wim Leers’s picture

https://www.drupal.org/project/schemata looks interesting, thanks for that!

@Grayside You seem to have a lot of experience with REST APIs, API documentation in general and Swagger in specific. Would you be interested in creating a (very rough) prototype of what that would/should look like according to you? I'd love to bring this to Drupal 8, but I'm no expert in this area, even though I'm tasked with improving this. So I'd love to learn from you, and hopefully even work with you to bring this to Drupal core in version 8.3 in early 2017!

Wim Leers’s picture

@kalinchernev Woah, lots of great questions! I don't have well-informed answers. Same question for you as I asked Grayside: Would you be interested in creating a (very rough) prototype of what that would/should look like according to you?

kalinchernev’s picture

Hi @Wim Leers,
Honestly, I think the solution could be pretty simple. Even possibly an extension to the restui since it's already having a good UI for endpoints configurations.
So, the functionality UI could be something like this:

Drupal REST UI swagger specification endpoint

It's oversimplified and probably dreamy. The idea being that the site builder configures the endpoint of the specification, which is generated for example from the yaml files. Then, the consumer can access a specification, which could look like this https://www.drupal.org/files/issues/example-swagger-spec.json_.tar_.gz
Basically, this is the specification that can be used by swagger-ui or other prettifying applications, either an embed in Drupal itself or another app.
I have to be honest that I have too little experience with D8 yet to dive into quick prototype module from scratch scenario to be good enough for core. That's why I'm thinking more into using existing tools.

dawehner’s picture

Yeah I think one big deal for actually supporting swagger could be to be able to provide the right json schema for our resources.
Sadly our recources are pretty flexible, given that, for example fields are per bundle. Providing a valid json schema could be pretty hard.

tedbow’s picture

@dawehner re:

Sadly our resources are pretty flexible, given that, for example fields are per bundle. Providing a valid json schema could be pretty hard.

Perhaps we could use Swagger "Specification Extensions" for this and other differences.

In Swagger you have parameters for each resource endpoint. We could add something "x-bundle-parameters" which would list fields by bundle.

dawehner’s picture

Well, we should try to provide as few changes as possible, because external tools will not understand our drupalisms :)

Grayside’s picture

Generating the Schema

See Schemata for how I approached generating JSON Schema from the Typed Data API. I made the decision to make it bundle centric, which works well for directly associating with content, but less effective for Swagger. Still, it can serve as a basis for Swagger, which was my intention with the module. One of the headaches with it was identifying how to interpret data constraints. They are semi-declarative right now.

Next steps down that path are to look at how REST API Doc is doing REST plugin/route analysis to identify available REST resources and methods and weave that into a Schema, and pull relevant bits of configuration as sensible defaults for title, description, and other context/boilerplate text.

Having a Swagger description should not be optional. Every enabled REST endpoint should automatically have a Swagger endpoint, at least as an option to enable or disable. Even if you don't want to make it public, that is an access decision, meanwhile we're talking about developer empowerment for effective maintenance of the system.

The approach I took in Schemata was to treat each description format as a new serializer. A schema format associated with the REST resource URL can route to provide the schema in lieu of the content. JSON-serialized entities are described by JSON Schema. HAL-serialized entities are described by HAL JSON Schema. In this approach, enabling JSON-schema for a given resource is just another format to activate.

Curating the Manual Content

It's easy to overlook the less automatic parts of the specification. Basic descriptions of things to provide context can be important. Titles, introductory paragraphs, key links, and extended resource descriptions may all be part of this.

Entity, Bundle, and Field description text becomes a lot more important in the context of machine-generated specifications, as they now serve as documentation outside the normal context of the Drupal site. You want as many of those fields filled in as possible, and the text cannot rely on context from breadcrumbs, form widgets, and so on to lend meaning.

Configuration can store overrides/additions to what can be pulled out of site configuration (e.g., Site Name can be repurposed as the title of the Swagger Spec, but maybe you want Site Name API, or Site Name Swagger Specification). Often the content management for Swagger is handled by technical writers, or at least people that will edit the docs much more often than reconfigure the API behavior itself, so I expect different permissions for the form elements and possibly a separate page-per-resource(-and-schema-format).

Viewing the Documentation

Some APIs rely on standing tools, others embed a "viewer app" like Swagger UI with either little customization or major, difficult-to-maintain customization. It often ends up as a non-trivial project for organizations that want their Swagger docs to look good and flow with the rest of the API documentation. For that reason, the API documentation/community/portal/management providers and packages often consume Swagger.

I recommend seeing if something emerges in Drupal Contrib, rather than trying to provide a viewer in Core.

Testing the Schema Experience

So without a viewing tool, how might we see what we produce?

Grayside’s picture

We should avoid vendor-specific extensions if possible, as that would partially defeat the interoperability would hope to gain. I haven't looked into it, but maybe if the embedded JSON Schema is structured as a oneOf selection of every available bundle we will convey the same effect.

tedbow’s picture

FileSize
142.4 KB
151.7 KB

I am experimenting with implementing the Swagger API in the Waterwheel module. I am working in swagger branch. In Waterwheel we currently have a basic REST resource for discovering other REST resources. We are looking into replacing this resource discovery with a route that returns Swagger compatible JSON that details on all the resources and parameters.
Right now I am working under the assumption that REST entity points will stay in their current form and and trying just to try to document that in Swagger compatible JSON.

We would also use this Swagger compatible JSON to create REST API documentation page via Swagger UI. The Swagger UI is working somewhat it displaying all resources and even lets you test out REST calls directly in the browser. Right now I only have that part working for GET.

The specification seems pretty flexible
Re: @dawehner

Sadly our resources are pretty flexible, given that, for example fields are per bundle. Providing a valid json schema could be pretty hard.

I see now the Swagger supports this type of schema using "discriminator" fields. Based on a value of 1 field it determines which sub schema to use. So this is basically our bundle field.
From Swagger Docs: http://swagger.io/specification/#referenceObject (scroll down to "Composition and Inheritance (Polymorphism)")

While composition offers model extensibility, it does not imply a hierarchy between the models. To support polymorphism, Swagger adds the support of the discriminator field. When used, the discriminator will be the name of the property used to decide which schema definition is used to validate the structure of the model.

I am testing this out now but it seems like Swagger would let us have Node schema(for base fields) which could be extended by an Article schema, Page schema and all other bundles(for bundle specific fields). The Node schema would have a "type" field which in Swagger would be the discriminator.

Here are couple screenshot of the Swagger UI so far:

dawehner’s picture

@tedbow
Is that part of the jsonschema specification or part of the swagger specification? Do you mind providing a link for more information about it?

tedbow’s picture

@dawehner I have updated my comment above with a link.
It looks like discriminator is part of Swagger/OpenAPI Specification

Here is a related issue against the OpenAPI Specification: Make schema object compatible with JSON Schema draft4

It seems "discriminator" is a swagger specific keyword inside the OpenAPI Specification. In that issue people are arguing whether that and other Swagger specific keywords are necessary or if discriminator could be replaced with oneOf from the JSON Schema.

tedbow’s picture

FileSize
30.43 KB

Just wanted to update this issue with my progress on getting Open API specification(fka Swagger) document produced for Drupal 8 REST module. I will also include an idea of how this might be integrated into core.

Current work is on this branch: https://github.com/tedbow/waterwheel/tree/8.x-2-swagger-schemata(mirrored from D.O.)
Requires this version of Schemata: https://github.com/tedbow/schemata (pull request open)

Currently the Waterwheel module provides an Open API specification JSON download file. Here is sample export: https://www.drupal.org/files/issues/entities.json_.txt
You can import this file into tools that support the Open API spec. The most useful tool I have found is the Swagger Editor which provides detail documenation.

  1. Goto the Swagger Editor demo: http://editor.swagger.io/#/
  2. Upload the sample entities.json file
  3. The left side of the screen will provide REST API docs for the site.

The Swagger Editor is an Open Source project: https://github.com/swagger-api/swagger-editor

The current documenation pages(using Swagger UI) and JSON files are available at /water-wheel/swagger-ui/list-resources

I have made small video detailing this: http://youtu.be/cYzQP77P56A

Core inclusion!?

Open API JSON

I think just having the ability to download the JSON file of the Open API Spec would be extremely useful.
Using any JSON viewing application a developer should be able to determine how to make REST requests.
Using a tool like Swagger Editor gives detailed REST docs. Developers could download and run the project locally or use the online service.

Generate docs

The Swagger UI project as used in the Waterwheel may be able provide on site documentation of REST Resource. If Swagger UI turns out not to fit Drupal's needs we could generate our own documenation.

If we end up needing to create our own generated documenation pages I think it is of utmost importance the generated docs solely rely on the Open API spec export to create the documentation pages. This would mean:

  1. The documenation pages should not use the type data manager or any other entity/resource inspection to generate the documenation
  2. We would be dogfooding our own REST specification export.
  3. If the generated docs cannot be made solely using the exported spec file it means the spec file does not completely describe the sites REST API and should be fixed.

This seems pretty far from the current issue description but it would serve the same purpose.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Wim Leers’s picture

Wim Leers’s picture

Status: Active » Closed (works as designed)

I think we're seeing consolidation on https://www.drupal.org/project/openapi. Both the https://github.com/acquia/reservoir and https://github.com/contentacms/contenta_jsonapi distributions are using it. It works for core's REST as well as for https://www.drupal.org/project/jsonapi.

Therefore closing this issue. This is solved by contrib. This doesn't need to be tracked in Drupal core anymore.