Examples

If you have not done so already, install Meldio on your computer using the start building guide.

Our first example, Star Wars API, illustrates how easy it is to create a fully functional GraphQL endpoint with Meldio. With just a simple schema definition, Meldio creates a powerful GraphQL endpoint with support for filtering, ordering, aggregation and paging operations.

The second example, Todo App, incorporates a React and Relay web application backed by Meldio server. This example illustrates Meldio's security features and mutations.

Star Wars API

Setup

We'll start by cloning the swapi repo from Github:

git clone https://github.com/meldio/swapi

Next, let's install the dependencies:

cd swapi
npm install

At this point, the Star Wars API example is ready.

Schema Definition

Open up the schema definition file, schema.sdl and note the following:

  • Each of the key elements in the Star Wars universe (i.e. Person, Film, Planet, Species, Starship and Vehicle) is defined as a type that implements Node interface.
  • Each Node type has a @rootConnection directive, allowing us to list all of its objects.
  • Film type has @rootPluralId directive on the episodeId field, allowing us to access a film using episode number.
  • producers field on Film type is an array of Strings where elements are required (i.e. non-null).
  • Node types are interconnected using node connections.
  • Starship and Vehicle implement Craft interface that defines some common fields. Then Person and Film types establish a node connection to the Craft interface meaning that connection can take on any object of the type that implements the Craft interface.

Start Meldio

Schema definition is all we need for swapi, so let's start Meldio in the run mode:

meldio run

Meldio will build the project and start the server that binds to port 9090. We can now run a number of sophisticated queries without writing a single line of code.

Following Connections

Open the swapi endpoint, http://localhost:9090/graphql, and let's run a query that fetches data about episode 6, along with some basic data on each species, craft, character and planet that appears in that episode:

{
  episode(episodeId: 6) {
    id
    title
    episodeId
    releaseDate
    species {
      edges {
        node {
          id
          name
          classification
        }
      }
    }
    craft {
      edges {
        node {
          ... on Node {
            id
          }
          name
          model
          class
        }
      }
    }
    characters {
      edges {
        node {
          id
          name
        }
      }
    }
    planets {
      edges {
        node {
          id
          name
        }
      }
    }
  }
}

This will fetch film information and 54 related objects in one round-trip to the server, where the same would require 55 requests to the server with a canonical REST API.

Ordering

Now, let's list all starships in the descending order of maximum megalights (mglt) and cost:

{
  allStarships(orderBy: [
    {node: {mglt: DESCENDING}},
    {node: {costInCredits: DESCENDING}}
  ]) {
    edges {
      node {
        id
        name
        model
        mglt
        costInCredits
      }
    }
  }
}

Filtering

Han Solo is looking for a decently fast starship on a budget? No problem, just run the following query:

{
  allStarships(filterBy: {
    node: {
      mglt: {gte: 50, lte: 100},
      costInCredits: {lt: 125000}
    }
  }) {
    edges {
      node {
        id
        name
        model
        mglt
        costInCredits
      }
    }
  }
}

Paging

Paging through the data set is also very straightforward. Simply add a cursor field on the edge and use first: n / after: cursor or last: n / before: cursor arguments on the connection. Add pageInfo object to determine if there is a previous/next page and the values for start and end cursors:

{
  allFilms(
    orderBy: {node: {episodeId: ASCENDING}},
    first: 3,
    after: "Y29ubmVjdGlvbjoy" # cursor that corresponds to episode 3
  ) {
    pageInfo {
      hasPreviousPage
      hasNextPage
      startCursor
      endCursor
    }
    edges {
      cursor
      node {
        id
        title
        episodeId
      }
    }
  }
}

Aggregations

Meldio supports standard count, sum, average, min and max aggregations. Count aggregation can also take a filter to count a subset of the overall data set. Note that aggregations are constrained by filters on connections but not by paging:

{
  allPlanets(first: 3) {
    numberOfPlanets: count
    numWithLongDays: count(filterBy: {node: {rotationPeriod: {gt: 26}}})
    avgRotationalPeriod: average(node: rotationPeriod)
    maxRotationalPeiod: max(node: rotationPeriod)
    minRotationalPeriod: min(node: rotationPeriod)
    totalPopulaton: sum(node: population)
    edges {
      node {
        id
        name
        diameter
        rotationPeriod
        orbitalPeriod
        gravity
        population
      }
    }
  }
}

Nested Connections

Following nested connections is very straightforward, too. For example, here we fetch episode 6 id and title, all characters that appear in this episode, and for each character all craft that they are piloting:

{
  episode(episodeId: 6) {
    id
    title
    characters {
      edges {
        node {
          id
          name
          craft {
            edges {
              node {
                name
                model
              }
            }
          }
        }
      }
    }
  }
}

Todo App

Setup

We'll start by cloning the todoapp repo from Github:

git clone https://github.com/meldio/todoapp

Next, let's install the dependencies:

cd todoapp
npm install

Initializing Meldio

Next, we need to initialize the Todo app with:

meldio init

Meldio will prompt for a number of settings and offer default values:

  • Project name (hit Enter to accept default)
  • Version (accept default)
  • MongoDB connection URI (accept default)
  • Meldio server host (accept default)
  • Meldio server port (accept default)
  • Authentication providers. Facebook, Google and Github will be selected. Hit Enter to accept.

At this point, Meldio will provide OAuth redirect URIs for Facebook, Google and Github authentication. We will need these URIs to complete the next three steps.

Facebook Authentication

Run through the following steps to setup Facebook Authentication:

  1. You will first need to create a new Facebook application
  2. Click on the Add a New App button in the top right section of the page
  3. Select Website as the platform
  4. Enter the app name, e.g. "Todo App", then click on Create New Facebook App ID button
  5. Choose any category and click on the Create App ID button
  6. Click on the Skip Quick Start button in the top right section of the page
  7. Go to the Settings section on the left-hand navigation bar, then select Advanced tab
  8. Scroll down to Valid OAuth redirect URIs field and copy and paste the URI that Meldio provided for Facebook
  9. Hit the Save Changes button on the bottom of the page
  10. Select Basic tab on the top
  11. Copy and paste App ID into the Meldio prompt, hit Enter
  12. Click on the Show button to reveal the App Secret and type in your Facebook password
  13. Copy and paste the App Secret back into the Meldio prompt

Google Authentication

Run through the following steps to setup Google Authentication:

  1. You will need to open Google Developers Console
  2. Click on the Select a project dropdown in the top right-hand section on the page
  3. Select Create a project... option
  4. Enter the project name, select email preferences, agree to the terms and click on the Create button
  5. Once the app is created, you will be redirected to the app dashboard
  6. Click on the Enable and Manage APIs link
  7. Select Credentials on the left-hand side nav bar
  8. Click on the OAuth consent screen in the top nav bar
  9. Enter Product name shown to users and click on the Save button
  10. Click on the Create credentials button and select OAuth client ID
  11. Select Web application under Application type
  12. Set the name of the app, e.g. Todo App
  13. Add two Authorized JavaScript origins: http://localhost:3000 and http://localhost:9000
  14. To set Authorized redirect URIs copy and paste the URI that Meldio provided for Google
  15. Click on the Create button
  16. You will get a popup with values for Client ID and Client Secret
  17. Copy and paste Client ID and Client Secret into the Meldio prompt

Github Authentication

Run through the following steps to setup Github Authentication:

  1. You will first need to create a new Github application
  2. Click the Register new application button at the top right of the page
  3. Enter the Application name (e.g. Todo App), Homepage URL (e.g. http://localhost:3000) and Authorization callback URL that Meldio provided for Github
  4. Click on the Register application button
  5. Copy and paste Client ID and Client Secret into the Meldio prompt

Start Meldio

We can now start Meldio:

meldio run

Meldio will build the project and start the server that binds to port 9000.

Schema Definition

Let's review the todoapp schema definition in server/schema.sdl:

  • There are two Node types - User and Todo - connected with a NodeConnection
  • User type has @rootViewer(field: "viewer") directive which instructs Meldio to create a root field viewer of type User that will return currently logged in user
  • Named filters are defined on a NodeConnection to Todo which are an alternative to more verbose ad-hoc filterBy expressions
  • Six mutations are defined corresponding to user actions within the app

Mutations

Schema defines six mutations that correspond to user actions within the app:

Each mutation that affects the number or status of todos returns a viewer object to allow the client app to query the todos connection for the number of all and completed todos following the mutation.

Permissions

Permissions are defined in the server/permissions.js file.

Users are only allowed to fetch their own User and Todo objects.

Any logged in user can execute addTodo, markAllTodos and removeCompletedTodos mutations. The last two mutations' implementations ensure they only affect the current user's todos so they do not need more restrictive permissions. However, permissions on mutations that operate on a specific todo (removeTodo, renameTodo and changeTodoStatus) check if the current user owns that todo and allow the mutation only if that is the case.

New OAuth Provider Hook

The new OAuth provider hook is defined in server/hooks/newOAuthProvider.js. It is executed whenever Meldio encounters a new OAuth provider profile.

Todo app uses the default implementation created by meldio init command. The hook tries to match the new profile with an existing user using email. If there is a match, the hook simply returns the user's id and Meldio associates this new OAuth provider profile with that user. If the profile is not matched with an existing user, a new user object is created using the information obtained from the provider profile (e.g. name, emails, avatar).

The advantage of this approach is that it allows the app users to login using different OAuth providers and get to the same user profile, provided they use the same emails across providers.

Simple Query

Open up the todoapp endpoint, http://localhost:9000/graphql, and try the following query:

{
  viewer {
    id
    firstName
    lastName
    emails
    profilePictureUrl
    todos {
      numberOfAllTodos: count(filter: ALL)
      numberOfCompletedTodos: count(filter: COMPLETED)
      edges {
        node {
          id
          text
          complete
        }
      }
    }
  }
}

Meldio will respond with:

{
  "data": {
    "viewer": null
  }
}

Since you are not logged in, Meldio returns null for the current user. Click on one of the three authentication options to login. Now, if you execute the query again, you will see your profile information and an empty list of todos. Try to execute a couple addTodo mutations, then run this query again.

Running the App

This example includes a slightly modified Todo web app from the Relay framework examples. To run the app, keep Meldio running, open up a new terminal window and run the following from the todoapp directory:

npm start

You can now access the app running on http://localhost:3000.