Back

Building a finance service on Yahoo using GraphQL

Building a finance service on Yahoo using GraphQL

In a case study for an application to a well-known German investment fund company, I implemented a GraphQL service that reads financial data from Yahoo.

image

Last year in 2023 I graduated with a Master's degree. I was looking for a job.

One of my first job interviews was with a investment fund company that was looking for a software developer to optimize its internal processes based on software tools.

I don't like it at all when the HR department keeps asking me the kind of questions I was asked in the university exams. Please, stop it! That's really no fun for anyone.

So I was really excited that the company chose a short case study for me. Here we go:

💡 Setting: The backend part of the task is recommended to be completed with Python or Node. All other choices of libraries are up to you. Please provide the solution as a private Github repository, with easy instructions on how to build and run the application

💡 Task: Implement an API with yahoo finance to pull some financial data for a company of your choice. Implement a GraphQL server that is suitable as a backend to query data. Keep your GraphQL schema simple to where the company is represented and you’re able to access the financial data via one of it’s fields

GraphQL vs. REST

I already had some experience with GraphQL, but not too much. Like any architectural decision, there are advantages and disadvantages. The technologies were specified by the case study. But I also intended to have some arguments about the architectural decision in mind.

Both technologies are obviously used to build interfaces between systems. But what are the key differences? Let us get a quick overview.

GraphQL

The main feature of GraphQL is the ability to request and receive only the requested data. Typically, a single endpoint is used for all operations, which simplifies communication between clients and servers.

image

The clients send a GraphQl query. The GraphQl server interprets this and collects all the necessary data, possibly from different sources, and returns the result in JSON format.

We have learnt that with GraphQL, it is the client and not the server that decides what data is required. This offers some advantages that REST cannot offer.

  1. High performance
  2. Huge flexibility
  3. Easy versioning

REST

REST is built around the principles of stateless communication and standard HTTP methods. It is very easy to set up and very lightweight, which is why it has become the standard technology on the market.

But... There are different implementations and most of the ones I have seen do not fulfil the REST standards. It does not force you to follow any specific guidance. As a result, many interfaces become a complete mess.

A well-defined REST API is great and will certainly suffice for most projects. However, many large corporations such as Meta and co. have completely different scaling problems. At this point, it is worth taking a look at the advantages of GraphQL.

image

Set up Apollo GraphQL

There are some projects that implement GraphQL. In my opinion, Apollo GraphQL is the best I have tested so far. Setting up the GraphQL server with Apollo is not rocket science.

import {ApolloServer} from 'apollo-server';
import {schema} from './data/schema';

const server = new ApolloServer({
    schema,
    introspection: true,
});

server.listen({port: process.env.PORT}).then(({url}) => {
    console.info(`Server is running: ${url}:${process.env.PORT}`);
});

Familiarise yourself with the configuration of the Apollo server. There are a variety of settings. I simply add the GraphQL schema and enable client introspection to use the Apollo GraphQL sandbox.

The sandbox is a ready-to-use client to test the GraphQL implementation. It is comparable to Swagger for REST API. As soon as I have started the server, I can access the sandbox via the localhost.

The sandbox is a really powerful tool for the development of GraphQL. I highly recommend it to everyone.

image

Don't reinvent the wheel - Yahoo Finance

Yahoo does not provide developers with an official API, but there is a large open source community for Yahoo financial data.

To query these data, the yahoo-finance2 package is used. The package has a high download rate compared to others, which corresponds to a good quality. Moreover, the package is actively maintained and well documented.

For this I have implemented a really simple adapter to get information about stocks and their historical performance. There is more data. It's worth taking a look at the useful documentation.

import YahooFinance from 'yahoo-finance2';

export const YahooFinancialAdapter = {
    readQuote: async (symbol: string) => {
        return await YahooFinance.quote(symbol);
    },
    readHistory: async (args: {
        symbol: string,
        from: string,
        to: string,
        interval: "1d" | "1wk" | "1mo"
    }) => {
        return await YahooFinance.historical(args.symbol, {
            period1: args.from,
            period2: args.to,
            interval: args.interval
        });
    },
};

GraphQL schema

GraphQL requires a schema that is written in the query language. It provides a blueprint that defines the structure of the data that clients can query from the GraphQL server.

The great thing about it: The schema provides type safety. It outlines the available data types, the relationships between them and the operations that clients can perform on them.

So I defined a QuoteType to get some standard information about a requested stock and a HistoryType to get the historical performance of stocks.

import { gql } from "apollo-server"

export const quoteType = gql`
  type Quote {
    language: String
    region: String
    currency: String
    shortName: String
    longName: String
    market: String
    marketCap: Float
    regularMarketPrice: Float
    regularMarketDayHigh: Float
    regularMarketDayLow: Float
    regularMarketVolume: Float
  }
`;

export const historyType = gql`
  type History {
    date: String
    open: Float
    high: Float
    low: Float
    close: Float
    adjClose: Float
    volume: Float
  }
`;

Simply add them, including the QueryType, to makeExecutableSchema to create the schema.

import {historyType} from "./model/history";
import {quoteType} from './model/quote';
import {queryType, resolvers as queryResolvers} from './query';
import {makeExecutableSchema} from "@graphql-tools/schema";

export const schema = makeExecutableSchema({
    typeDefs: [queryType, quoteType, historyType],
    resolvers: {
        ...queryResolvers,
    }
});

GraphQL query & resolver

To get data from GraphQL, I also need to create a query. A GraphQL query is basically a string that tells the server what kind of data the client is looking for based on the data types.

A simple query to get some user information of the user with the id 123 could look like this:

query {
  user(id: 123) {
    name
    email
  }
}

To deploy a query, I need to implement it with Apollo GraphQL and connect it to a resolver that I have previously added in the schema. In GraphQL, a resolver is a function that is responsible for retrieving the data for a specific field in a GraphQL query.

So let's take a look at the definition of the QueryType and the resolver:

import { gql } from "apollo-server"
import { YahooFinancialAdapter } from "../adapter/yahoo-financial-adapter";

export const queryType = gql`
  type Query {
    quote(symbol: String): Quote
    history(symbol: String, from: String, to: String, interval: String): [History]
  }
`;

export const resolvers = {
  Query: {
    quote: async (_parent: any, args: {
      symbol: string
    }) => {
      return await YahooFinancialAdapter.readQuote(args.symbol);
    },
    history: async (_parent: any, args: any) => {
      return await YahooFinancialAdapter.readHistory(args) ?? [];
    },
  }
};

Using the sandbox to query data

I have now done everything I need to start the Apollo GraphQL sandbox to test my implementation.

The dashboard of the sandbox is divided into 3 areas. On the left-hand side is the documentation of the interface that was generated on the basis of the schema. This feature is absolutely amazing!

Queries can be made in the centre of the dashboard. Auto-completion is also available.

On the right-hand side, the results are returned in JSON format.

image

Finally, I would like to test the implementation. Please tell me how Apple performed in the first two weeks of September. So I only have to add these variables to get the result:

{
  "symbol": "AAPL",
  "from": "2023-09-01",
  "to": "2023-09-13",
  "interval": "1d",
}

Conclusion

What a nice case study! The scope was absolutely perfect for a job application. I don't want to spend days coding for every job application. GraphQL feels very flexible at first glance and with Apollo I had a very powerful development tool that was really fun to write and test queries with.

Anyway. At the end of the day, I took another opportunity at MHP - A Porsche Company as a technology strategy consultant.

💡 You can find the project and all the code in my Github Repository.

You are welcome to get in touch with me if you have any questions.