Ghost/core/server/api
Rish 4f0ca2914f Updated members schema validation for name
no issue

- Removed minimum length requirement for `name` as its possible to have empty name for a member
2019-10-10 17:26:56 +05:30
..
canary Updated members schema validation for name 2019-10-10 17:26:56 +05:30
shared Migrated schedules controller to v2 2019-08-07 14:51:36 +02:00
v0.1 🐛 Fixed "unsaved changes" modal displaying when post has been saved 2019-10-07 22:59:19 +01:00
v2 Removed members endpoint from admin v2 api 2019-10-10 17:51:46 +07:00
index.js 💡 Added canary api endpoint 2019-08-09 20:46:49 +05:30
README.md Added comments for Ghost API 2019-05-06 14:49:25 +02:00

API Versioning

Ghost supports multiple API versions. Each version lives in a separate folder e.g. api/v0.1, api/v2. Next to the API folders there is a shared folder, which contains shared code, which all API versions use.

NOTE: v0.1 is deprecated and we won't touch the shared folder at all. The v0.1 folder contains the API layer which we have used since Ghost was born.

Stages

Each request goes through the following stages:

  • input validation
  • input serialisation
  • permissions
  • query
  • output serialisation

The framework we are building pipes a request through these stages in respect of the API controller configuration.

Frame

Is a class, which holds all the information for request processing. We pass this instance by reference. Each function can modify the original instance. No need to return the class instance.

Structure

{
  original: Object,
  options: Object,
  data: Object,
  user: Object,
  file: Object,
  files: Array
}

Example

{
  original: {
    include: 'tags'
  },
  options: {
    withRelated: ['tags']
  },
  data: {
    posts: []
  }
}

API Controller

A controller is no longer just a function, it's a set of configurations.

Structure

edit: function || object
edit: {
  headers: object,
  options: Array,
  data: Array,
  validation: object | function,
  permissions: boolean | object | function,
  query: function
}

Examples

edit: {
  headers: {
    cacheInvalidate: true
  },
  // Allowed url/query params
  options: ['include']
  // Url/query param validation configuration
  validation: {
    options: {
      include: {
        required: true,
        values: ['tags']
      }
    }
  },
  permissions: true,
  // Returns a model response!
  query(frame) {
    return models.Post.edit(frame.data, frame.options);
  }
}
read: {
  // Allowed url/query params, which will be remembered inside `frame.data`
  // This is helpful for READ requests e.g. `model.findOne(frame.data, frame.options)`.
  // Our model layer requires sending the where clauses as first parameter.
  data: ['slug']
  validation: {
    data: {
      slug: {
        values: ['eins']
      }
    }
  },
  permissions: true,
  query(frame) {
    return models.Post.findOne(frame.data, frame.options);
  }
}
edit: {
  validation() {
    // custom validation, skip framework
  },
  permissions: {
    unsafeAttrs: ['author']
  },
  query(frame) {
    return models.Post.edit(frame.data, frame.options);
  }
}