My Learning Projects

A few months ago, I decided that I needed to have a project where I learn React and GraphQL, and instead of doing a normal tutorial, I also decided that I was going to build a completely independent project that I would host online as part of my portfolio. The TL;DR here is that I didn’t ever finish it, but I did learn what I needed for GraphQL at least, and that I realized that I don’t have the skills to come up with a React component system all on my own.

The project lives in the Bytes Zone, and it is officially called the Lego Marvel Browser. The project pitch is this: A web app that allows you to browse Lego Marvel sets based on relational data found in the Marvel API. For example, you could find all the Lego sets that have Black Widow as a minifigure. The app wasn’t going to be making any money (which is something you agree to when you get a Marvel API key) but rather demonstrate my ability with the tech stack, and to help convince people to hire me.

Stage 1: GraphQL

I decided that I was going to start with the GraphQL side of things, since I’m much more comfortable with back-end web work: interfacing with APIs, HTTP return codes, and so on.

BTW, hattip to Data is Plural for providing both of these APIs!

Marvel API

First, I got my Marvel API token, saved it to an .env file, and cranked out this marvel.js file

    const crypto = require('crypto');
    const axios = require('axios');
    const { buildSchema } = require('graphql');

    const BASE_URL = 'https://gateway.marvel.com/v1/public';

    const getParams = () => {
        let public = process.env.MARVEL_API_PUBLIC_KEY;
        let private = process.env.MARVEL_API_PRIVATE_KEY;
        let ts = Date.now().toString();
        let data = ts + private + public;
        let hash = crypto.createHash('md5').update(data).digest('hex');

        return {
            apikey: public,
            ts: ts,
            hash: hash
        };
    };

    exports.schema = buildSchema(`
    type Query {
        characters: [Character]
        comics: [Comic]
        series: [Series]
    }

    type Character {
        id: Int!
        name: String!
        description: String!
        modified: String!
        comics: [Comic]!
        series: [Series]!
    }

    type Comic {
        id: Int!
        title: String!
        issueNumber: String!
        description: String!
        modified: String!
        characters: [Character]!
        series: Series!
    }

    type Series {
        id: Int!
        title: String!
        description: String!
        modified: String!
        comics: [Comic]!
        characters: [Character]!
    }
    `);

    const characters = () => {
        return axios.get(`${BASE_URL}/characters`, {params: getParams()})
            .then(res => {
                return res.data.data.results;
            })
            .catch(function(error) { console.log(error); });
    };

    const comics = () => {
        return axios.get(`${BASE_URL}/comics`, {params: getParams()})
            .then(res => {
                return res.data.data.results;
            })
            .catch(error => console.log(error));
    };

    const series = () => {
        return axios.get(`${BASE_URL}/series`, {params: getParams()})
            .then(res => {
                return res.data.data.results;
            })
            .catch(error => console.log(error));
    };


    exports.characters = characters;
    exports.comics = comics;
    exports.series = series;

Then, I have this server.js file.

    #!/usr/bin/env node
    require('dotenv').config()

    const express = require('express')
    const cors = require('cors')
    const graphqlHTTP = require('express-graphql')
    const graphql_schema = require('./src/schema.js')

    const app = express()
    app.use(cors())

    const graphql = graphqlHTTP({
        schema: graphql_schema.schema,
        rootValue: graphql_schema.rootValue,
        graphiql: true,
    });

    app.use('/graphql', graphql)
    app.listen(4000)
    console.log('Server is running on localhost:4000/graphql')

N.B: The graphql_schema variable loads a file that doesn’t exist, so that this code will fail if you try to run it. When I find out where the working code for this exists, and if I remember to, I’ll update the repo and this blog post. I’m a little embarrassed, but this is a minor thing, so I won’t worry too much about it

BrickLink API: a bust

It was at this point I decided to leave the Marvel API and work on the Lego side. What I didn’t realize at the time was that the API provided by BrickLink is for store operators, so their API wasn’t actually available.

Then, I looked at the listing for the dataset in Data is Plural, and I found out that the whole dataset can be downloaded in bulk. If I ever pick up this project again, I’ll consider loading that data into a SQLite table and using that as a datasource, but only if it has pictures, and the TOS allows it.

At the time, I decided that I was just going to wrap the Marvel API, and build a React app to display the info. However, I started to lose interest, since my original vision wasn’t possible.

Stage 2: React

With this stage, I honestly didn’t get that far. This is when I realized that I was going to need to do more work learning React and web design before I start building out an app.

That said, I was able to put this App.js together

    import React, { Component } from "react";
    import { request } from 'graphql-request';
    import {hot} from "react-hot-loader";
    import "./App.css";

    class App extends Component{
        constructor(props) {
            super(props);
            this.state = { characters: [] };
        }
        componentDidMount() {
            const query = `query {
                characters {
                        name
                        comics {
                          description
                        }
                }
            }`;
            request('http://localhost:4000/graphql', query)
                .then(res => {
                    this.setState({ characters: res.characters });
                });
        }
        render() {
            return (
                <div className="App">
                    <h1> Hello, World!</h1>
                        <ul>
                        { this.state.characters.map(character => <Character name=charactor.name description=character.description >;}) }
                        </ul>
                </div>
            );
        }
    }

    export default hot(module)(App);

As you can see, it’s not that complex; I’m simply iterating over the data and putting it into a component called Character. Well, here is Character.js:

    import { Component } from 'react';

    export default class Character extends Component{
        render() {
            return (
                    <ul>
                    <li>{this.props.name}</li>
                    <li>{this.props.description}</li>
                    </ul>
            );
        }
    }

A simple ul element. My CSS doesn’t even have any rules for that component, so it just renders as default HTML 5. Nothing special.

My Personal End Point

It was at this point that I realized that I wasn’t going to be able to make thing that actually looked good. And the fact that I was only wrapping the Marvel API and that this project wasn’t really going to go anywhere interesting, I decided to stop working on it. I had learned what I needed to learn.

And what did I learn exactly?

  1. I learned about how to build GraphQL schemas, and how to populate those schemas with data. If I ever work on a large GraphQL project, I have the basics down and I can look at the documentation whenever I need to. I feel pretty good about my project in this regard
  2. I learned about Axios, at least a little bit. I have a feeling that I’ll be using this library in any future JS projects.
  3. I learned a bit about Babel and Webpack. Not enough to be really confident, but I do know what they are now.
  4. I learned that I don’t know enough about React to be able to make things look like what I want them to look like. I know the basic flow of things, but I don’t know it well enough to be able to come up with a non-trivial implementation without considerable effort, like I was able to do with the GraphQL side of things
  5. I don’t know enough about web design to be able to just wing it like I was planning. I’m going to have to do a lot more practice with just the design aspect of things before I can go building apps from scratch.

So, even though I didn’t finish this project, I learned quite a bit, and really, that’s what these kinds of projects should be. I was too ambitious with this project: I should have seen it like it was: a learning project, not a portfolio one.

The future?

I think that I could make a GraphQL wrapper for the Marvel API, and delete the React part entirely. Also, I think that once I get more practice with React and web design, I might come up with a good portfolio project, just not this one.

Call for comments

Feel free to make comments below (unless you are a spammer, I check!). What do you think that I should try next?