Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mhart/simple-relay-starter
A very simple starter for React Relay using Browserify
https://github.com/mhart/simple-relay-starter
Last synced: 3 months ago
JSON representation
A very simple starter for React Relay using Browserify
- Host: GitHub
- URL: https://github.com/mhart/simple-relay-starter
- Owner: mhart
- License: mit
- Created: 2015-09-08T16:16:05.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2017-01-28T04:21:15.000Z (almost 8 years ago)
- Last Synced: 2024-05-12T10:42:48.925Z (8 months ago)
- Language: JavaScript
- Size: 27.3 KB
- Stars: 156
- Watchers: 7
- Forks: 16
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-graphql - simple-relay-starter - A very simple starter for React Relay using Browserify. (Examples / JavaScript Examples)
- awesome-relay - Simple Relay Starter - A Browserify version of the [Relay Starter Kit](https://github.com/relayjs/relay-starter-kit). (Starter Kits)
README
simple-relay-starter
--------------------A simple example of how to get started with
[Relay](https://facebook.github.io/relay/) using some slightly different
approaches to [relay-starter-kit](https://github.com/relayjs/relay-starter-kit)
that may make it easier to navigate for first-time users, especially Node.js
users.Unlike [relay-starter-kit](https://github.com/relayjs/relay-starter-kit), this
project uses [Browserify](http://browserify.org/) instead of
[Webpack](https://webpack.github.io/), does not use a proxy for the GraphQL
endpoint and does not require ES6 features for any server-side code, so it can
be run directly with `node` – resulting in less boilerplate and making it
easier to understand the code.Example
-------```console
$ npm install
$ npm run build
$ npm start
```Then navigate to [http://localhost:3000](http://localhost:3000) and
observe the network request to `/graphql` that Relay makes to retrieve the data.For development, you can use:
```console
$ npm run dev
```Which will build the schema and then watch for any file changes, rebuilding the
schema and/or restarting the server as necessary.Here are the files involved:
`App.js`:
```js
var React = require('react')
var Relay = require('react-relay')// A simple top-level component that illustrates how to render Relay-fetched
// data using props. In this case Relay will populate a `user` property that
// has a collection of `widgets` based on the queries and fragments we give it
// further below.
class App extends React.Component {
render() {
return (
User: {this.props.user.name}
Widgets:
{/* In schema/schema.js we define a Connection between users and widgets */}
{/* Connections use `edges` and `node` to hold paging info and child items */}
{this.props.user.widgets.edges.map(edge =>
- {edge.node.name} (Global ID: {edge.node.id})
)}
)
}
}// The component we need to export is a Relay wrapper around our App component
// from above. It declares the GraphQL fragments where we list the properties
// we want to be fetched – eg, user.name, user.widgets.edges, etc
exports.Container = Relay.createContainer(App, {
fragments: {
// The property name here reflects what is added to `this.props` above.
// This template string will be parsed by babel-relay-plugin when we browserify.
user: () => Relay.QL`
fragment on User {
name,
widgets(first: 10) {
edges {
node {
id,
name,
},
},
},
}
`,
},
})// The Relay root container needs to know what queries will occur at the top
// level – these configurations are currently called Routes in Relay, but this
// name is misleading and under review so we don't use it here.
exports.queries = {
name: 'AppQueries', // can be anything, just used as an identifier
params: {},
queries: {
// We can use this shorthand so long as the component we pair this with has
// a fragment named "user", as we do above.
user: () => Relay.QL`query { user }`,
},
}
````browser.js`:
```js
var React = require('react')
var ReactDOM = require('react-dom')
var Relay = require('react-relay')
var App = require('./App')// This file is the entry point on the browser – browserify will compile it, as
// well as App.js and any other client-side dependencies and create
// public/bundle.js which will be requested by public/index.htmlReactDOM.render(
// At the top of a Relay tree is the root container, which we pass our
// wrapped App component to, as well as the query configuration ("route"). If
// we need to render a different component, say as a result of a navigation
// event, then we would update it here.
// We also illustrate the use of the onReadyStateChange handler in case
// there's a network error, etc
{ if (error) console.error(error) }} />,document.getElementById('content')
)
````public/index.html`:
```html```
`server.js`:
```js
var express = require('express')
var graphqlHttp = require('express-graphql')
var schema = require('./schema/schema')// The server is just a simple Express app
var app = express()// We respond to all GraphQL requests from `/graphql` using the
// `express-graphql` middleware, which we pass our schema to.
app.use('/graphql', graphqlHttp({schema: schema}))// The rest of the routes are just for serving static files
app.use('/relay', express.static('./node_modules/react-relay/dist'))
app.use('/', express.static('./public'))app.listen(3000, function() { console.log('Listening on 3000...') })
````schema/database.js`:
```js
// We use these types to hold data and resolve from GraphQL types in our schemafunction User(id, name) {
this.id = id.toString()
this.name = name
}function Widget(id, userId, name) {
this.id = id.toString()
this.userId = userId.toString()
this.name = name
}// In a realistic system, the get functions below would return objects from a
// datastore like a DB or a REST API instead of an in-memory store like this.
// You can also return promises for async fetchingvar users = [new User(1, 'Anonymous')]
var widgets = [
new Widget(1, 1, 'What\'s-it'),
new Widget(2, 1, 'Who\'s-it'),
new Widget(3, 1, 'How\'s-it'),
]module.exports = {
User: User,
Widget: Widget,
getUser: function(id) { return users.filter(function(u) { return u.id == id })[0] },
getAnonymousUser: function() { return users[0] },
getWidget: function(id) { return widgets.filter(function(w) { return w.id == id })[0] },
getWidgetsByUser: function(userId) { return widgets.filter(function(w) { return w.userId == userId }) },
}
````schema/schema.js`:
```js
var GraphQL = require('graphql')
var GraphQLRelay = require('graphql-relay')
var db = require('./database')// This module exports a GraphQL Schema, which is a declaration of all the
// types, queries and mutations we'll use in our system.// Relay adds some specific types that it needs to function, including Node, Edge, Connection
// Firstly we need to create the Node interface in our system. This has nothing
// to do with Node.js! In Relay, Node refers to an entity – that is, an object
// with an ID.// To create this interface, we need to pass in a resolving function as the
// first arg to nodeDefinitions that can fetch an entity given a global Relay
// ID. The second arg can be used to resolve an entity into a GraphQL type –
// but it's actually optional, so we'll leave it out and use isTypeOf on the
// GraphQL types further below.var nodeDefinitions = GraphQLRelay.nodeDefinitions(function(globalId) {
var idInfo = GraphQLRelay.fromGlobalId(globalId)
if (idInfo.type == 'User') {
return db.getUser(idInfo.id)
} else if (idInfo.type == 'Widget') {
return db.getWidget(idInfo.id)
}
return null
})// We can now use the Node interface in the GraphQL types of our schema
var widgetType = new GraphQL.GraphQLObjectType({
name: 'Widget',
description: 'A shiny widget',// Relay will use this function to determine if an object in your system is
// of a particular GraphQL type
isTypeOf: function(obj) { return obj instanceof db.Widget },// We can either declare our fields as an object of name-to-definition
// mappings or a closure that returns said object (see userType below)
fields: {
id: GraphQLRelay.globalIdField('Widget'),
name: {
type: GraphQL.GraphQLString,
description: 'The name of the widget',
},
},
// This declares this GraphQL type as a Node
interfaces: [nodeDefinitions.nodeInterface],
})var userType = new GraphQL.GraphQLObjectType({
name: 'User',
description: 'A person who uses our app',
isTypeOf: function(obj) { return obj instanceof db.User },// We use a closure here because we need to refer to widgetType from above
fields: function() {
return {
id: GraphQLRelay.globalIdField('User'),
name: {
type: GraphQL.GraphQLString,
description: 'The name of the user',
},
// Here we set up a paged one-to-many relationship ("Connection")
widgets: {
description: 'A user\'s collection of widgets',// Relay gives us helper functions to define the Connection and its args
type: GraphQLRelay.connectionDefinitions({name: 'Widget', nodeType: widgetType}).connectionType,
args: GraphQLRelay.connectionArgs,// You can define a resolving function for any field.
// It can also return a promise if you need async data fetching
resolve: function(user, args) {
// This wraps a Connection object around your data array
// Use connectionFromPromisedArray if you return a promise instead
return GraphQLRelay.connectionFromArray(db.getWidgetsByUser(user.id), args)
},
},
}
},
interfaces: [nodeDefinitions.nodeInterface],
})// Now we can bundle our types up and export a schema
// GraphQL expects a set of top-level queries and optional mutations (we have
// none in this simple example so we leave the mutation field out)
module.exports = new GraphQL.GraphQLSchema({
query: new GraphQL.GraphQLObjectType({
name: 'Query',
fields: {
// Relay needs this to query Nodes using global IDs
node: nodeDefinitions.nodeField,
// Our own root query field(s) go here
user: {
type: userType,
resolve: function() { return db.getAnonymousUser() },
},
},
}),
})
```