simple:rest

v1.2.1Published 2 years ago

Compatibility

Compatible with Meteor 2.4

This repository provides versions for the package simple:rest that are compatible with latest Meteor. This is necessary because the author is not maintaining package anymore.

Changes

  • v1.2.1
    • Update simple:json-routes to 2.3.0
  • v1.2.0
    • api.versionsFrom on Package.onUse was changed from 1.1.0.2 to 2.4.

One-step JSON API for your publications and methods

meteor add simple:rest

Add this package to get an automatic JSON HTTP API for all of your Meteor app's publications and methods. It works with all of your existing security rules and authentication. This can be useful for many things:

  • Build a simple native mobile app on top of your Meteor app's data
  • Expose an API for other people to get data
  • Integrate with other frameworks and platforms without having to integrate a DDP client

Keep in mind that this package is literally calling your Meteor methods and publications. This means if you have any nice packages that do roles, authentication, permissions, etc. for your app, those packages should still work just fine over HTTP.

For a lot of examples of how to define and call methods and publications, see the unit tests in this package.

Table of contents

  1. Using the API
  2. Publications
  3. Methods
  4. Collection insert/update/remove
  5. Example code with JQuery
  6. Additional tools
  7. Listing all API methods
  8. Cross origin requests
  9. Authentication
  10. Logging in over HTTP
  11. Change log

Publications

By default, publications are accessible via an HTTP GET request at the URL:

GET /publications/<publication-name>

The response is an object where the keys are the collections in the publication, and each collection has an array of documents. Note that a publication can publish from many collections at once.

1{
2  collectionName: [
3    { _id: "xxx", otherData: "here" },
4    { _id: "yyy", otherData: "here" }
5  ]
6}

Options for Meteor.publish added by this package

  • url: Set a custom URL, which can contain parameters. The parameters are in the form :argument-number, so in this case :0 means that segment of the URL will be passed as the first argument. Note that URL arguments are always strings, so you might need to parse to get an integer if you are expecting one.
  • httpMethod: Pick the HTTP method that must be used when calling this endpoint. The default is "get".
1Meteor.publish("widgets-above-index", function (index) {
2  return Widgets.find({index: {$gt: parseInt(index, 10)}});
3}, {
4  url: "widgets-with-index-above/:0",
5  httpMethod: "post"
6});

Call the above publication with:

POST /widgets-with-index-above/4

Methods

By default, methods are accessible with a POST request at the following URL:

POST /methods/<method-name>

Arguments are passed as JSON or query-encoded data in the message body. Since the arguments are positional, the arguments are in array form. Here's an example of how you can call a method using Meteor's http package:

1HTTP.post("/methods/addNumbers", {
2  data: [2, 2]
3}, function (err, res) {
4  console.log(res); // 4
5});

Passing options about a method

To pass options about your method's HTTP endpoint, you can use an alternate method definition syntax that comes from this package – Meteor.method — that takes an options object as its last argument:

1Meteor.method("return-five", function () {
2  return 5;
3}, options);

You can also pass options without using the other syntax by calling SimpleRest.setMethodOptions before the Method definition:

1SimpleRest.setMethodOptions('return-five', options);
2
3Meteor.methods({
4  'return-five': function () {
5    return 5;
6  }
7});

Available options

  • url: Define a custom URL for this method.
  • getArgsFromRequest: A function that accepts a Node request object and returns an array which will be passed as arguments to your method. If this option is not passed, simple:rest expects that the request body is a JSON array that maps to the method arguments, or a single JSON object that is passed as the only argument to the method.
  • httpMethod: Set the HTTP method which must be used when calling this API endpoint. The default is "post".
1Meteor.method("add-numbers", function (a, b) {
2  return a + b;
3}, {
4  url: "add-numbers",
5  getArgsFromRequest: function (request) {
6    // Let's say we want this function to accept a form-encoded request with
7    // fields named `a` and `b`.
8    var content = request.body;
9
10    // Since form enconding doesn't distinguish numbers and strings, we need
11    // to parse it manually
12    return [ parseInt(content.a, 10), parseInt(content.b, 10) ];
13  }
14})

Setting HTTP status code

By default, successful method requests will respond with status code 200 and errors will respond with status code 400. To override this in your method:

1this.setHttpStatusCode(201);

Collection methods

The default Meteor collection methods (insert, update, and remove) are also automatically exposed when this package is added. Don't worry, they follow the exact same security rules as in your Meteor DDP app, and allow/deny still works perfectly.

Inserting into a collection

POST /<collection-name>

The body of the request should be a JSON-serialized document to insert into the database.

Updating a document in a collection

PATCH /<collection-name>/<_id>

The body of the request should be a JSON-serialized set of fields to update in the document.

Deleting a document from a collection

DELETE /<collection-name>/<_id>

No request body is necessary for deletion, it just deletes the document with the specified _id.

Choosing Which Collections Should Have Endpoints

By default all collections get endpoints automatically.

To specify only certain collections, in your server code before you define any collections:

1SimpleRest.configure({
2  collections: ['widgets', 'doodles']
3});

Where the strings must match the collection name string you pass to the Mongo.Collection constructor.

For no collection endpoints:

1SimpleRest.configure({
2  collections: []
3});

Using ObjectIDs

If any of your collections use ObjectIDs instead of string IDs, tell simple:rest about them and everything will work fine:

1SimpleRest.configure({
2  objectIdCollections: ['widgets', 'doodles']
3});

Where the strings must match the collection name string you pass to the Mongo.Collection constructor.

Example code with JQuery

Here is how you might call your shiny new HTTP API using JQuery. Note that you must set contentType to "application/json", because by default JQuery uses form serialization rather than JSON serialization.

1// Calling a method
2$.ajax({
3  method: "post",
4  url: "/methods/add-all-arguments",
5  data: JSON.stringify([1, 2, 3]),
6  contentType: "application/json",
7  success: function (data) {
8    console.log(data); // 6
9  }
10});
11
12// Getting data from a publication
13$.get("/publications/widgets", function (data) {
14  console.log(data.widgets.length); // 11
15});

Listing all API methods

This package defines a special publication that publishes a list of all of your app's API methods. Call it like this:

GET /publications/api-routes

The result looks like:

1{ "api-routes": [
2  {
3    "_id": "/users/login",
4    "methods": [
5      "options",
6      "post"
7    ],
8    "path": "/users/login"
9  },
10  {
11    "_id": "/users/register",
12    "methods": [
13      "options",
14      "post"
15    ],
16    "path": "/users/register"
17  },
18  {
19    "_id": "/publications/api-routes",
20    "methods": [
21      "get"
22    ],
23    "path": "/publications/api-routes"
24  },
25  {
26    "_id": "/widgets",
27    "methods": [
28      "options",
29      "post"
30    ],
31    "path": "/widgets"
32  },
33  {
34    "_id": "/widgets/:_id",
35    "methods": [
36      "options",
37      "patch",
38      "options",
39      "delete"
40    ],
41    "path": "/widgets/:_id"
42  },
43  ...
44] }

Note that this package also generates OPTIONS endpoints for all of your methods. This is to allow you to enable cross-origin requests if you choose to, by returning an Access-Control-Allow-Origin header. More on that below.

Error Handling

We recommend that you add our default error handler like so:

1JsonRoutes.ErrorMiddleware.use(RestMiddleware.handleErrorAsJson);

This will convert any Meteor.Errors that your methods throw to useful JSON responses.

You can set error.statusCode before you throw the error if you want a particular status code returned.

Cross-origin requests

If you would like to use your API from the client side of a different app, you need to return a special header. You can do this by hooking into a method on the simple:json-routes package, like so:

1// Enable cross origin requests for all endpoints
2JsonRoutes.setResponseHeaders({
3  "Cache-Control": "no-store",
4  "Pragma": "no-cache",
5  "Access-Control-Allow-Origin": "*",
6  "Access-Control-Allow-Methods": "GET, PUT, POST, DELETE, OPTIONS",
7  "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With"
8});

Change Log

1.1.0

  • Add SimpleRest.setMethodOptions to enable mdg:validated-method mixin.

1.0.0

  • Move auth functionality to separate middleware packages:
    • rest-bearer-token-parser: Parse a standard bearer token
    • authenticate-user-by-token: Authenticate a Meteor.user via auth token

0.2.3

  • Add httpMethod option to Meteor.method and Meteor.publish. With it, you

can make a method callable via GET or a publication via POST, or anything else.

0.2.2

  • Add getArgsFromRequest option to Meteor.method and Meteor.publish.
  • Improved error handling to better match DDP error handling

0.2.1

Start checking for token expirations.

0.2.0

Changed api for insert/update/remove to be more RESTful. Now you call it with:

POST /collection
PATCH /collection/:_id
DELETE /collection/:_id

0.1.2

Initial publicized release.