constructor(registry, type, request = {}) {
    this.registry = registry;
    this.type = type;
    this.request = request;

    /**
      Use this property on a model serializer to whitelist attributes that will be used in your JSON payload.

      For example, if you had a `blog-post` model in your database that looked like

      ```
      {
        id: 1,
        title: 'Lorem ipsum',
        createdAt: '2014-01-01 10:00:00',
        updatedAt: '2014-01-03 11:42:12'
      }
      ```

      and you just wanted `id` and `title`, you could write

      ```js
      Serializer.extend({
        attrs: ['id', 'title']
      });
      ```

      and the payload would look like

      ```
      {
        id: 1,
        title: 'Lorem ipsum'
      }
      ```

      @property attrs
      @public
    */
    this.attrs = this.attrs || undefined; // this is just here so I can add the doc comment. Better way?

    /**
      Use this property on a model serializer to specify related models you'd like to include in your JSON payload. (These can be considered default server-side includes.)

      For example, if you had an `author` with many `blog-post`s and you wanted to sideload these, specify so in the `include` key:

      ```js
      createServer({
        models: {
          author: Model.extend({
            blogPosts: hasMany()
          })
        },
        serializers: {
          author: Serializer.extend({
            include: ['blogPosts']
          });
        }
      })
      ```

      Now a response to a request for an author would look like this:

      ```
      GET /authors/1

      {
        author: {
          id: 1,
          name: 'Link',
          blogPostIds: [1, 2]
        },
        blogPosts: [
          {id: 1, authorId: 1, title: 'Lorem'},
          {id: 2, authorId: 1, title: 'Ipsum'}
        ]
      }
      ```

      You can also define `include` as a function so it can be determined dynamically.
      
      For example, you could conditionally include a relationship based on an `include` query parameter:

      ```js
      // Include blog posts for a GET to /authors/1?include=blogPosts
      
      Serializer.extend({
        include: function(request) {
          if (request.queryParams.include === "blogPosts") {
            return ['blogPosts'];
          } else {
            return [];
          }
        }
      });
      ```

      **Query param includes for JSONAPISerializer**

      The JSONAPISerializer supports the use of `include` query parameter to return compound documents out of the box.

      For example, if your app makes the following request

      ```
      GET /api/authors?include=blogPosts
      ```

      the `JSONAPISerializer` will inspect the query params of the request, see that the blogPosts relationship is present, and then proceed as if this relationship was specified directly in the include: [] array on the serializer itself.

      Note that, in accordance with the spec, Mirage gives precedence to an ?include query param over a default include: [] array that you might have specified directly on the serializer. Default includes will still be in effect, however, if a request does not have an ?include query param.

      Also note that default includes specified with the `include: []` array can only take a single model; they cannot take dot-separated paths to nested relationships.

      If you'd like to set a default dot-separated (nested) include path for a resource, you have to do it at the route level by setting a default value for `request.queryParams`:

      ```js
      this.get('/users', function(schema, request) => {
        request.queryParams = request.queryParams || {};
        if (!request.queryParams.include) {
          request.queryParams.include = 'blog-posts.comments';
        }

        // rest of route handler logic
      });
      ```

      @property include
      @public
    */
    this.include = this.include || []; // this is just here so I can add the doc comment. Better way?

    /**
      Set whether your JSON response should have a root key in it.

      *Doesn't apply to JSONAPISerializer.*

      Defaults to true, so a request for an author looks like:

      ```
      GET /authors/1

      {
        author: {
          id: 1,
          name: 'Link'
        }
      }
      ```

      Setting `root` to false disables this:

      ```js
      Serializer.extend({
        root: false
      });
      ```

      Now the response looks like:

      ```
      GET /authors/1

      {
        id: 1,
        name: 'Link'
      }
      ```

      @property root
      @public
    */
    this.root = this.root || undefined; // this is just here so I can add the doc comment. Better way?

    /**
      Set whether related models should be embedded or sideloaded.

      *Doesn't apply to JSONAPISerializer.*

      By default this false, so relationships are sideloaded:

      ```
      GET /authors/1

      {
        author: {
          id: 1,
          name: 'Link',
          blogPostIds: [1, 2]
        },
        blogPosts: [
          { id: 1, authorId: 1, title: 'Lorem' },
          { id: 2, authorId: 1, title: 'Ipsum' }
        ]
      }
      ```

      Setting `embed` to true will embed all related records:

      ```js
      Serializer.extend({
        embed: true
      });
      ```

      Now the response looks like:

      ```
      GET /authors/1

      {
        author: {
          id: 1,
          name: 'Link',
          blogPosts: [
            { id: 1, authorId: 1, title: 'Lorem' },
            { id: 2, authorId: 1, title: 'Ipsum' }
          ]
        }
      }
      ```

      You can also define `embed` as a function so it can be determined dynamically.
    */
    this.embed = this.embed || undefined; // this is just here so I can add the doc comment. Better way?
    this._embedFn = isFunction(this.embed) ? this.embed : () => !!this.embed;

    /**
      Use this to define how your serializer handles serializing relationship keys. It can take one of three values:

      - `included`, which is the default, will serialize the ids of a relationship if that relationship is included (sideloaded) along with the model or collection in the response
      - `always` will always serialize the ids of all relationships for the model or collection in the response
      - `never` will never serialize the ids of relationships for the model or collection in the response

      @property serializeIds
      @public
    */
    this.serializeIds = this.serializeIds || undefined; // this is just here so I can add the doc comment. Better way?

    /**
      Primary Key name of the model

      Defaults to 'id', so a request for an author looks like:

      ```
      GET /authors/1

      {
        author: {
          id: 1,
          name: 'Link'
        }
      }
      ```

      Setting `primaryKey` to 'authorId changes this:

      ```js
      Serializer.extend({
        primaryKey: 'authorId'
      });
      ```

      Now the response looks like:

      ```
      GET /authors/1

      {
        author: {
          authorId: 1,
          name: 'Link'
        }
      }
      ```

      @property primaryKey
      @public
    */
    this.primaryKey = this.primaryKey || undefined; // this is just here so I can add the doc comment. Better way?
  }
Serializers are responsible for formatting your route handler's response.

  The application serializer will apply to every response. To make specific customizations, define per-model serializers.

  ```js
  import { createServer, RestSerializer } from 'miragejs';

  createServer({
    serializers: {
      application: RestSerializer,
      user: RestSerializer.extend({
        // user-specific customizations
      })
    }
  })
  ```

  Any Model or Collection returned from a route handler will pass through the serializer layer. Highest priority will be given to a model-specific serializer, then the application serializer, then the default serializer.

  Mirage ships with three named serializers:

  - **JSONAPISerializer**, to simulate JSON:API compliant API servers:

    ```js
    import { createServer, JSONAPISerializer } from 'miragejs';

    createServer({
      serializers: {
        application: JSONAPISerializer
      }
    })
    ```

  - **ActiveModelSerializer**, to mock Rails APIs that use AMS-style responses:

    ```js
    import { createServer, ActiveModelSerializer } from 'miragejs';

    createServer({
      serializers: {
        application: ActiveModelSerializer
      }
    })
    ```

  - **RestSerializer**, a good starting point for many generic REST APIs:

    ```js
    import { createServer, RestSerializer } from 'miragejs';

    createServer({
      serializers: {
        application: RestSerializer
      }
    })
    ```

  Additionally, Mirage has a basic Serializer class which you can customize using the hooks documented below:

  ```js
  import { createServer, Serializer } from 'miragejs';

  createServer({
    serializers: {
      application: Serializer
    }
  })
  ```

  When writing model-specific serializers, remember to extend from your application serializer so shared logic is used by your model-specific classes:

  ```js
  import { createServer, Serializer } from 'miragejs';

  const ApplicationSerializer = Serializer.extend()

  createServer({
    serializers: {
      application: ApplicationSerializer,
      blogPost: ApplicationSerializer.extend({
        include: ['comments']
      })
    }
  })
  ```

  @class Serializer
  @constructor
  @public