├── client
├── style
│ └── style.css
├── index.js
└── index.html
├── .gitignore
├── .babelrc
├── server
├── models
│ ├── index.js
│ ├── lyric.js
│ └── song.js
├── schema
│ ├── schema.js
│ ├── song_type.js
│ ├── lyric_type.js
│ ├── root_query_type.js
│ └── mutations.js
└── server.js
├── index.js
├── README.md
├── webpack.config.js
└── package.json
/client/style/style.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_STORE
3 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env", "react"]
3 | }
4 |
--------------------------------------------------------------------------------
/server/models/index.js:
--------------------------------------------------------------------------------
1 | require('./song');
2 | require('./lyric');
3 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const app = require('./server/server');
2 |
3 | app.listen(4000, () => {
4 | console.log('Listening');
5 | });
6 |
--------------------------------------------------------------------------------
/client/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | const Root = () => {
5 | return
Lyrical
6 | };
7 |
8 | ReactDOM.render(
9 | ,
10 | document.querySelector('#root')
11 | );
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Lyrical-GraphQL
2 |
3 | Starter project from a GraphQL course on Udemy.com
4 |
5 | ### Setup
6 |
7 | - Run `npm install --legacy-peer-deps` in the root of the project to install dependencies
8 | - Access the application at `localhost:4000` in your browser
9 |
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/server/schema/schema.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 | const graphql = require('graphql');
3 | const { GraphQLSchema } = graphql;
4 |
5 | const RootQueryType = require('./root_query_type');
6 | const mutations = require('./mutations');
7 |
8 | module.exports = new GraphQLSchema({
9 | query: RootQueryType,
10 | mutation: mutations
11 | });
12 |
--------------------------------------------------------------------------------
/server/models/lyric.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | const Schema = mongoose.Schema;
3 |
4 | const LyricSchema = new Schema({
5 | song: {
6 | type: Schema.Types.ObjectId,
7 | ref: 'song'
8 | },
9 | likes: { type: Number, default: 0 },
10 | content: { type: String }
11 | });
12 |
13 | LyricSchema.statics.like = function(id) {
14 | const Lyric = mongoose.model('lyric');
15 |
16 | return Lyric.findById(id)
17 | .then(lyric => {
18 | ++lyric.likes;
19 | return lyric.save();
20 | })
21 | }
22 |
23 | mongoose.model('lyric', LyricSchema);
24 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 |
4 | module.exports = {
5 | entry: './client/index.js',
6 | output: {
7 | path: '/',
8 | filename: 'bundle.js'
9 | },
10 | module: {
11 | rules: [
12 | {
13 | use: 'babel-loader',
14 | test: /\.js$/,
15 | exclude: /node_modules/
16 | },
17 | {
18 | use: ['style-loader', 'css-loader'],
19 | test: /\.css$/
20 | }
21 | ]
22 | },
23 | plugins: [
24 | new HtmlWebpackPlugin({
25 | template: 'client/index.html'
26 | })
27 | ]
28 | };
29 |
--------------------------------------------------------------------------------
/server/schema/song_type.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | const graphql = require('graphql');
3 | const { GraphQLObjectType, GraphQLString, GraphQLID, GraphQLList } = graphql;
4 | const LyricType = require('./lyric_type');
5 | const Song = mongoose.model('song');
6 |
7 | const SongType = new GraphQLObjectType({
8 | name: 'SongType',
9 | fields: () => ({
10 | id: { type: GraphQLID },
11 | title: { type: GraphQLString },
12 | lyrics: {
13 | type: new GraphQLList(LyricType),
14 | resolve(parentValue) {
15 | return Song.findLyrics(parentValue.id);
16 | }
17 | }
18 | })
19 | });
20 |
21 | module.exports = SongType;
22 |
--------------------------------------------------------------------------------
/server/schema/lyric_type.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | const graphql = require('graphql');
3 | const {
4 | GraphQLObjectType,
5 | GraphQLList,
6 | GraphQLID,
7 | GraphQLInt,
8 | GraphQLString
9 | } = graphql;
10 | const Lyric = mongoose.model('lyric');
11 |
12 | const LyricType = new GraphQLObjectType({
13 | name: 'LyricType',
14 | fields: () => ({
15 | id: { type: GraphQLID },
16 | likes: { type: GraphQLInt },
17 | content: { type: GraphQLString },
18 | song: {
19 | type: require('./song_type'),
20 | resolve(parentValue) {
21 | return Lyric.findById(parentValue).populate('song')
22 | .then(lyric => {
23 | console.log(lyric)
24 | return lyric.song
25 | });
26 | }
27 | }
28 | })
29 | });
30 |
31 | module.exports = LyricType;
32 |
--------------------------------------------------------------------------------
/server/models/song.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | const Schema = mongoose.Schema;
3 |
4 | const SongSchema = new Schema({
5 | title: { type: String },
6 | user: {
7 | type: Schema.Types.ObjectId,
8 | ref: 'user'
9 | },
10 | lyrics: [{
11 | type: Schema.Types.ObjectId,
12 | ref: 'lyric'
13 | }]
14 | });
15 |
16 | SongSchema.statics.addLyric = function(id, content) {
17 | const Lyric = mongoose.model('lyric');
18 |
19 | return this.findById(id)
20 | .then(song => {
21 | const lyric = new Lyric({ content, song })
22 | song.lyrics.push(lyric)
23 | return Promise.all([lyric.save(), song.save()])
24 | .then(([lyric, song]) => song);
25 | });
26 | }
27 |
28 | SongSchema.statics.findLyrics = function(id) {
29 | return this.findById(id)
30 | .populate('lyrics')
31 | .then(song => song.lyrics);
32 | }
33 |
34 | mongoose.model('song', SongSchema);
35 |
--------------------------------------------------------------------------------
/server/schema/root_query_type.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | const graphql = require('graphql');
3 | const { GraphQLObjectType, GraphQLList, GraphQLID, GraphQLNonNull } = graphql;
4 | const SongType = require('./song_type');
5 | const LyricType = require('./lyric_type');
6 | const Lyric = mongoose.model('lyric');
7 | const Song = mongoose.model('song');
8 |
9 | const RootQuery = new GraphQLObjectType({
10 | name: 'RootQueryType',
11 | fields: () => ({
12 | songs: {
13 | type: new GraphQLList(SongType),
14 | resolve() {
15 | return Song.find({});
16 | }
17 | },
18 | song: {
19 | type: SongType,
20 | args: { id: { type: new GraphQLNonNull(GraphQLID) } },
21 | resolve(parentValue, { id }) {
22 | return Song.findById(id);
23 | }
24 | },
25 | lyric: {
26 | type: LyricType,
27 | args: { id: { type: new GraphQLNonNull(GraphQLID) } },
28 | resolve(parnetValue, { id }) {
29 | return Lyric.findById(id);
30 | }
31 | }
32 | })
33 | });
34 |
35 | module.exports = RootQuery;
36 |
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const models = require('./models');
3 | const expressGraphQL = require('express-graphql');
4 | const mongoose = require('mongoose');
5 | const bodyParser = require('body-parser');
6 | const schema = require('./schema/schema');
7 |
8 | const app = express();
9 |
10 | // Replace with your Mongo Atlas URI
11 | const MONGO_URI = '';
12 | if (!MONGO_URI) {
13 | throw new Error('You must provide a Mongo Atlas URI');
14 | }
15 |
16 | mongoose.Promise = global.Promise;
17 | mongoose.connect(MONGO_URI);
18 | mongoose.connection
19 | .once('open', () => console.log('Connected to Mongo Atlas instance.'))
20 | .on('error', (error) =>
21 | console.log('Error connecting to Mongo Atlas:', error)
22 | );
23 |
24 | app.use(bodyParser.json());
25 | app.use(
26 | '/graphql',
27 | expressGraphQL({
28 | schema,
29 | graphiql: true
30 | })
31 | );
32 |
33 | const webpackMiddleware = require('webpack-dev-middleware');
34 | const webpack = require('webpack');
35 | const webpackConfig = require('../webpack.config.js');
36 | app.use(webpackMiddleware(webpack(webpackConfig)));
37 |
38 | module.exports = app;
39 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lyrical",
3 | "version": "1.0.0",
4 | "description": "Starter point for a graphQL course",
5 | "main": "index.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/StephenGrider/Lyrical-GraphQL"
9 | },
10 | "scripts": {
11 | "dev": "nodemon index.js --ignore client"
12 | },
13 | "author": "",
14 | "license": "ISC",
15 | "dependencies": {
16 | "apollo-client": "^0.8.1",
17 | "axios": "^0.15.3",
18 | "babel-core": "^6.22.1",
19 | "babel-loader": "^6.2.10",
20 | "babel-preset-env": "^1.1.8",
21 | "babel-preset-react": "^6.22.0",
22 | "body-parser": "^1.16.0",
23 | "connect-mongo": "^1.3.2",
24 | "css-loader": "^0.26.1",
25 | "express": "^4.14.0",
26 | "express-graphql": "0.6.1",
27 | "express-session": "^1.15.0",
28 | "graphql": "^0.8.2",
29 | "html-webpack-plugin": "^2.26.0",
30 | "lodash": "^4.17.4",
31 | "mongoose": "^7.3.1",
32 | "nodemon": "^2.0.22",
33 | "passport": "^0.3.2",
34 | "passport-local": "^1.0.0",
35 | "react": "^15.4.2",
36 | "react-apollo": "^0.9.0",
37 | "react-dom": "^15.4.2",
38 | "react-router": "^3.0.2",
39 | "style-loader": "^0.13.1",
40 | "webpack": "^2.2.0",
41 | "webpack-dev-middleware": "^1.9.0"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/server/schema/mutations.js:
--------------------------------------------------------------------------------
1 | const graphql = require('graphql');
2 | const { GraphQLObjectType, GraphQLString, GraphQLID } = graphql;
3 | const mongoose = require('mongoose');
4 | const Song = mongoose.model('song');
5 | const Lyric = mongoose.model('lyric');
6 | const SongType = require('./song_type');
7 | const LyricType = require('./lyric_type');
8 |
9 | const mutation = new GraphQLObjectType({
10 | name: 'Mutation',
11 | fields: {
12 | addSong: {
13 | type: SongType,
14 | args: {
15 | title: { type: GraphQLString }
16 | },
17 | resolve(parentValue, { title }) {
18 | return new Song({ title }).save();
19 | }
20 | },
21 | addLyricToSong: {
22 | type: SongType,
23 | args: {
24 | content: { type: GraphQLString },
25 | songId: { type: GraphQLID }
26 | },
27 | resolve(parentValue, { content, songId }) {
28 | return Song.addLyric(songId, content);
29 | }
30 | },
31 | likeLyric: {
32 | type: LyricType,
33 | args: { id: { type: GraphQLID } },
34 | resolve(parentValue, { id }) {
35 | return Lyric.like(id);
36 | }
37 | },
38 | deleteSong: {
39 | type: SongType,
40 | args: { id: { type: GraphQLID } },
41 | resolve(parentValue, { id }) {
42 | return Song.findByIdAndRemove(id);
43 | }
44 | }
45 | }
46 | });
47 |
48 | module.exports = mutation;
49 |
--------------------------------------------------------------------------------