├── .gitignore
├── .meteor
├── .finished-upgraders
├── .gitignore
├── .id
├── packages
├── platforms
├── release
└── versions
├── README.md
├── client
├── main.css
├── main.html
├── main.js
└── startup.js
├── imports
├── client
│ └── components
│ │ └── App.js
└── data
│ ├── resolvers.js
│ ├── schema.js
│ └── youtube-connector.js
├── package.json
└── server
└── main.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .idea/
3 |
--------------------------------------------------------------------------------
/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 |
--------------------------------------------------------------------------------
/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | xiq9w71e8d27gvk0cmi
8 |
--------------------------------------------------------------------------------
/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base # Packages every Meteor app needs to have
8 | mobile-experience # Packages for a great mobile UX
9 | mongo # The database Meteor supports right now
10 | blaze-html-templates # Compile .html files into Meteor Blaze views
11 | reactive-var # Reactive variable for tracker
12 | jquery # Helpful client-side library
13 | tracker # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css # CSS minifier run for production mode
16 | standard-minifier-js # JS minifier run for production mode
17 | es5-shim # ECMAScript 5 compatibility for older browsers.
18 | ecmascript # Enable ECMAScript2015+ syntax in app code
19 |
20 | autopublish # Publish all data to the clients (for prototyping)
21 | insecure # Allow all DB writes from clients (for prototyping)
22 |
--------------------------------------------------------------------------------
/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@1.3.2.4
2 |
--------------------------------------------------------------------------------
/.meteor/versions:
--------------------------------------------------------------------------------
1 | allow-deny@1.0.4
2 | autopublish@1.0.7
3 | autoupdate@1.2.9
4 | babel-compiler@6.6.4
5 | babel-runtime@0.1.8
6 | base64@1.0.8
7 | binary-heap@1.0.8
8 | blaze@2.1.7
9 | blaze-html-templates@1.0.4
10 | blaze-tools@1.0.8
11 | boilerplate-generator@1.0.8
12 | caching-compiler@1.0.4
13 | caching-html-compiler@1.0.6
14 | callback-hook@1.0.8
15 | check@1.2.1
16 | ddp@1.2.5
17 | ddp-client@1.2.7
18 | ddp-common@1.2.5
19 | ddp-server@1.2.6
20 | deps@1.0.12
21 | diff-sequence@1.0.5
22 | ecmascript@0.4.3
23 | ecmascript-runtime@0.2.10
24 | ejson@1.0.11
25 | es5-shim@4.5.10
26 | fastclick@1.0.11
27 | geojson-utils@1.0.8
28 | hot-code-push@1.0.4
29 | html-tools@1.0.9
30 | htmljs@1.0.9
31 | http@1.1.5
32 | id-map@1.0.7
33 | insecure@1.0.7
34 | jquery@1.11.8
35 | launch-screen@1.0.11
36 | livedata@1.0.18
37 | logging@1.0.12
38 | meteor@1.1.14
39 | meteor-base@1.0.4
40 | minifier-css@1.1.11
41 | minifier-js@1.1.11
42 | minimongo@1.0.16
43 | mobile-experience@1.0.4
44 | mobile-status-bar@1.0.12
45 | modules@0.6.1
46 | modules-runtime@0.6.3
47 | mongo@1.1.7
48 | mongo-id@1.0.4
49 | npm-mongo@1.4.43
50 | observe-sequence@1.0.11
51 | ordered-dict@1.0.7
52 | promise@0.6.7
53 | random@1.0.9
54 | reactive-var@1.0.9
55 | reload@1.1.8
56 | retry@1.0.7
57 | routepolicy@1.0.10
58 | spacebars@1.0.11
59 | spacebars-compiler@1.0.11
60 | standard-minifier-css@1.0.6
61 | standard-minifier-js@1.0.6
62 | templating@1.1.9
63 | templating-tools@1.0.4
64 | tracker@1.0.13
65 | ui@1.0.11
66 | underscore@1.0.8
67 | url@1.0.9
68 | webapp@1.2.8
69 | webapp-hashing@1.0.9
70 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Meteor Apollo Youtube Search
2 |
3 | ```js
4 | npm install
5 |
6 | meteor
7 | ```
8 |
9 | ## Contribute
10 | It'd be cool to make this example better! Help out!
11 |
--------------------------------------------------------------------------------
/client/main.css:
--------------------------------------------------------------------------------
1 | /* CSS declarations go here */
2 |
--------------------------------------------------------------------------------
/client/main.html:
--------------------------------------------------------------------------------
1 |
2 | Apollo Youtube Searcher
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/client/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import { render } from 'react-dom';
3 | import React from 'react';
4 | import { ApolloProvider } from 'react-apollo';
5 | import App from '/imports/client/components/App';
6 | import ApolloClient from 'apollo-client';
7 |
8 | const client = new ApolloClient();
9 |
10 | Meteor.startup(() => {
11 | render(
12 |
13 | , document.getElementById('root'));
14 | });
15 |
--------------------------------------------------------------------------------
/client/startup.js:
--------------------------------------------------------------------------------
1 | import { registerGqlTag } from 'apollo-client/gql';
2 |
3 | Meteor.startup(() => {
4 | registerGqlTag();
5 | });
6 |
--------------------------------------------------------------------------------
/imports/client/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-apollo';
3 |
4 | class App extends React.Component {
5 | constructor() {
6 | super();
7 | this.state = {
8 | keywords: "Apollo Stack"
9 | }
10 | }
11 | render() {
12 | const { youtubeVideos } = this.props;
13 | const videos = youtubeVideos && youtubeVideos.data;
14 | const searchCount = _.size(videos) || 0;
15 | let input;
16 | return (
17 |
18 |
Youtube Searcher
19 |
20 | {
26 | this.setState({keywords: e.target.value});
27 | }}
28 | className="form-control"
29 | placeholder="Enter search terms..."
30 | />
31 |
39 |
40 |
We found {searchCount} results
41 |
42 | {_.map(videos, ({ videoId, title, description }, index) => {
43 | return (
44 |
45 |
{title}
46 |
{description}
47 |
48 |
49 | );
50 | })}
51 |
52 |
53 | );
54 | }
55 | }
56 |
57 | function mapQueriesToProps() {
58 | return {
59 | youtubeVideos: {
60 | query: gql`
61 | query getKeywords($keywords: String) {
62 | data(keywords: $keywords) {
63 | title
64 | description
65 | videoId
66 | }
67 | }
68 | `,
69 | forceFetch: true,
70 | variables: {
71 | keywords: "Apollo Stack"
72 | }
73 | }
74 | }
75 | }
76 |
77 |
78 | export default connect({mapQueriesToProps})(App);
79 |
--------------------------------------------------------------------------------
/imports/data/resolvers.js:
--------------------------------------------------------------------------------
1 | import { Youtube } from '/imports/data/youtube-connector';
2 |
3 | const resolvers = {
4 | Query: {
5 | async data(root, { keywords }) {
6 | return Youtube.search(keywords);
7 | }
8 | }
9 | };
10 |
11 | export default resolvers;
12 |
--------------------------------------------------------------------------------
/imports/data/schema.js:
--------------------------------------------------------------------------------
1 | export default schema = [`
2 | type SearchResults {
3 | description: String,
4 | title: String,
5 | videoId: String
6 | }
7 | type Query {
8 | data(keywords: String): [SearchResults]
9 | }
10 | schema {
11 | query: Query
12 | }
13 | `];
14 |
--------------------------------------------------------------------------------
/imports/data/youtube-connector.js:
--------------------------------------------------------------------------------
1 | import rp from 'request-promise';
2 | export const Youtube = {
3 | search(keyword) {
4 | const maxResults = 25;
5 | const key = "AIzaSyCWx8epSrJ8dvlLn7YutD5qB2y_FBrEaRg";
6 | const uri = "https://www.googleapis.com/youtube/v3/search";
7 | const request = {
8 | key,
9 | part: "snippet",
10 | maxResults,
11 | order: "viewCount",
12 | q: keyword,
13 | type: "video",
14 | videoEmbeddable: true
15 | };
16 | const options = {
17 | uri,
18 | qs: request,
19 | headers: {
20 | 'User-Agent': 'Request-Promise'
21 | },
22 | json: true // Automatically parses the JSON string in the response
23 | };
24 | return rp(options).then((res) => {
25 | return res.items.map(({ snippet, id }) => {
26 | const videoId = id.videoId;
27 | return { videoId, ...snippet };
28 | });
29 | }).catch((err) => {
30 | console.error(err);
31 | });
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "apollo-youtube-search",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run"
6 | },
7 | "dependencies": {
8 | "apollo-client": "^0.3.9",
9 | "bluebird": "^3.4.0",
10 | "cls-bluebird": "^1.0.1",
11 | "continuation-local-storage": "^3.1.7",
12 | "express": "^4.13.4",
13 | "fbjs": "^0.8.3",
14 | "graphql": "^0.6.0",
15 | "graphql-tools": "^0.4.1",
16 | "http-proxy-middleware": "^0.15.0",
17 | "meteor-node-stubs": "~0.2.0",
18 | "react": "^15.1.0",
19 | "react-apollo": "^0.3.4",
20 | "react-dom": "^15.1.0",
21 | "react-redux": "^4.4.5",
22 | "redux": "^3.5.2",
23 | "request-promise": "^3.0.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/server/main.js:
--------------------------------------------------------------------------------
1 | import { apolloServer } from 'graphql-tools';
2 | import express from 'express';
3 | import proxyMiddleware from 'http-proxy-middleware';
4 | import schema from '/imports/data/schema';
5 | import resolvers from '/imports/data/resolvers';
6 |
7 | const GRAPHQL_PORT = 4000;
8 |
9 | const graphQLServer = express();
10 |
11 | graphQLServer.use('/graphql', apolloServer(async () => {
12 | return {
13 | graphiql: true,
14 | pretty: true,
15 | schema,
16 | resolvers
17 | };
18 | }));
19 |
20 | graphQLServer.listen(GRAPHQL_PORT, () => console.log(
21 | `GraphQL Server is now running on http://localhost:${GRAPHQL_PORT}`
22 | ));
23 |
24 | WebApp.rawConnectHandlers.use(proxyMiddleware(`http://localhost:${GRAPHQL_PORT}/graphql`));
25 |
--------------------------------------------------------------------------------