Building a stock market service on Yahoo using GraphQL
Building a stock market service on Yahoo using GraphQL
In a recent case study for a well-known German investment fund company, I implemented a GraphQL service that retrieves stock market data from Yahoo Finance.
Last year, in 2023, I completed my Master’s degree and began searching for a job.
One of my first interviews was with an investment fund company looking for a software architect to optimize its internal processes with software tools.
I’m not a fan of HR interviews that feel like university exams, filled with tedious, theoretical questions like "Please write an primality test algorithm for determining whether an input number is prime". Please, stop it! That's really no fun for anyone.
So, I was thrilled when the company assigned me a short case study instead. Here’s how it went:
💡 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 had some experience with GraphQL, but not extensively. Like any architectural decision, both GraphQL and REST have their pros and cons. The case study specified the technologies, but I also wanted to have some reasoning behind the architectural decision.
Both GraphQL and REST are used to build interfaces between systems. But what are the key differences? Here’s a quick overview:
GraphQL
The main feature of GraphQL is its ability to request and receive only the data you need. Typically, a single endpoint is used for all operations, simplifying communication between clients and servers.
Clients send a GraphQL query, the server interprets it, gathers the necessary data (potentially from multiple sources), and returns the result in JSON format.
With GraphQL, the client and not the server decides what data is required. This offers some advantages over REST:
- High performance
- Huge flexibility
- Easy versioning
REST
REST is built on the principles of stateless communication and standard HTTP methods. It’s easy to set up and lightweight, which is why it’s become the industry standard.
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.
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}`);
});
Familiarize yourself with the configuration of the Apollo server. There are various settings available. I simply added the GraphQL schema and enabled client introspection to use the Apollo GraphQL sandbox.
The sandbox is a ready-to-use client for testing GraphQL implementations. It’s comparable to Swagger for REST APIs. Once I started the server, I could access the sandbox via localhost.
The sandbox is an incredibly powerful tool for GraphQL development. I highly recommend it to everyone.
Don't reinvent the wheel - Yahoo Finance
Yahoo doesn’t provide an official API for developers, but there’s a robust open-source community for Yahoo financial data.
For this project, I used the yahoo-finance2 package. It has a high download rate, indicating good quality, and it’s actively maintained and well-documented.
I implemented a simple adapter to retrieve information about stocks and their historical performance. There’s more data available, so I recommend checking out the 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 written in its query language. The schema acts as a blueprint that defines the structure of the data clients can query from the GraphQL server.
The great thing about the schema is that it provides type safety. It outlines the available data types, the relationships between them, and the operations clients can perform.
I defined a QuoteType to retrieve 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 and resolver
To retrieve data from GraphQL, I also needed to create a query. A GraphQL query is 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 for a user with ID 123 might look like this:
query {
user(id: 123) {
name
email
}
}
To deploy a query, I implemented it with Apollo GraphQL and connected it to a resolver, which I had previously added to the schema. In GraphQL, a resolver is a function responsible for retrieving the data for a specific field in a GraphQL query.
Here’s 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
Now that everything is set up, I started the Apollo GraphQL sandbox to test my implementation. The sandbox dashboard is divided into three sections.
On the left is the auto-generated documentation of the interface based on the schema—a fantastic feature! Queries can be made in the center of the dashboard, with auto-completion available.
On the right, the results are returned in JSON format.
Finally, I wanted to test the implementation. For example, to see how Apple performed in the first two weeks of September, I added the following variables to get the result:
{
"symbol": "AAPL",
"from": "2023-09-01",
"to": "2023-09-13",
"interval": "1d",
}
Conclusion
This was a great case study! The scope was perfect for a job application. GraphQL feels very flexible at first glance, and with Apollo, I had a powerful development tool that made writing and testing.
Anyway. At the end of the day, I took another opportunity at MHP - A Porsche Company as a technology strategy consultant, which promises great opportunities. But that's a story for another time!
💡 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.