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.
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.
Open up the schema definition file, schema.sdl and note the following:
Node
interface.@rootConnection
directive, allowing us to list all of its objects.@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).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.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.
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.
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
}
}
}
}
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 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
}
}
}
}
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
}
}
}
}
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
}
}
}
}
}
}
}
}
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
Next, we need to initialize the Todo app with:
meldio init
Meldio will prompt for a number of settings and offer default values:
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.
Run through the following steps to setup Facebook Authentication:
Run through the following steps to setup Google Authentication:
http://localhost:3000
and http://localhost:9000
Run through the following steps to setup Github Authentication:
http://localhost:3000
) and Authorization callback URL that Meldio provided for GithubWe can now start Meldio:
meldio run
Meldio will build the project and start the server that binds to port 9000.
Let's review the todoapp schema definition in server/schema.sdl:
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 userNodeConnection
to Todo
which
are an alternative to more verbose ad-hoc filterBy
expressionsSchema 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 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.
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.
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.
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.