Browse Source

graphql project

pull/670/head
lee 4 years ago
parent
commit
4e93ee9f95
  1. 126
      subjects/graphql/README.md
  2. 0
      subjects/graphql/audit/README.md
  3. 119
      subjects/graphql/index.html
  4. 157
      subjects/graphql/lib/schema.js
  5. 101
      subjects/graphql/lib/schema.json

126
subjects/graphql/README.md

@ -0,0 +1,126 @@
## GraphQL
### Objectives
The objective of this project is to learn graphql query language by creating your own profile. It will be provided,\
by the platform, a graphql endpoint that is connected to the database. So you can query this endpoint to obtain the information you desire.\
**Note** that for security reasons some tables are private and some are public, you will only be provided with certain content.
Your profile must have at least:
- Basic user identification
- XP amount
- level
- grades
- skills
- statistics
### Instructions
> Here is a small introduction and advantages of graphQL, if you want to read more about graphQL you can visit there [site](https://graphql.org/)
GraphQL is a query language for any API endpoint and runtime. The syntax lets you specify what data you want to receive from that API.\
You must have in mind that this language is used for API endpoints and not database. Unlike SQL,\
graphql query does not go to your database directly but to your graphql API endpoint which can connect to a database or any other data source.
You are already familiar to REST, since REST is a robust methodology of creating APIs and not elastic/scalable.\
It can be at the same time painful, because it requires individual creation of each API, example: `v1/user/item/{id}`, `v1/post/item/{id}` and so on.
The main feature of graphql compared to REST is that it lets you ask for specific information. And even better then that is the nesting feature.
Lets take for instance the social network project, if the server had a Graphql API that was connected to the database we could query this API using graphql language:
```js
query {
user {
name
}
}
```
This simple query will return an array with the name of the users. Imagine if you wanted the `date_of_birth`,\
you could just add this attribute to the query, example:
```js
query {
user {
name
dateOfBirth
}
}
```
Example for the nesting fetching:
```js
query {
user(id: "13") {
name
dateOfBirth
followers {
id
name
}
}
}
```
For this example we ask for the users followers and request their names and ids.\
The examples above are simple examples, **note** that this query is require the introduction of variables(arguments)\
so it will return just one user, the user that as the id equal to `13`.
In graphql the usage of arguments can be specified in the schema of the API endpoint. Here is the *docs* for the graphql endpoint you are going to use, [Schema](https://01.alem.school/public/subjects/grapqhl)
<!-- EXPLAIN WHAT IS GOING TO HAPPEN -->
---
### Usage
> Here are the list of tables that you are available to query:
- **User table**:
| id | githubLogin |
| --- | ----------: |
| 1 | person1 |
| 2 | person2 |
| 3 | person3 |
- **Transactions table**:
| id | type | amount | userId | createdAt |
| --- | :--: | -----: | -----: | -------------------------------: |
| 1 | xp | 234 | 1 | 2019-03-14T12:02:23.168726+00:00 |
| 2 | xp | 1700 | 2 | 2019-03-14T12:02:23.168726+00:00 |
| 3 | xp | 175 | 3 | 2019-03-14T12:02:23.168726+00:00 |
- **Progress table**:
| id | userId | attrs | bestResultId | objectId |
| --- | :----: | -----------------------: | -----------: | -------: |
| 1 | 1 | `{"name": "memory", ...` | s | 198 |
| 2 | 2 | `{"name": "memory", ...` | s | 198 |
| 3 | 3 | `{"name": "memory", ...` | s | 198 |
- **Results table**:
| id | grade | progressId |
| --- | ----: | ---------: |
| 1 | 0 | 58 |
| 2 | 0 | 58 |
| 3 | 1 | 58 |
- **Object table**:
| id | grade | progressId |
| --- | ----: | ---------: |
| 1 | 0 | 58 |
| 2 | 0 | 58 |
| 3 | 1 | 58 |
This project will help you learn about:
- [Graphql](https://graphql.org/) language

119
subjects/graphql/index.html

@ -0,0 +1,119 @@
<!DOCTYPE html>
<html>
<head>
<title>Graphql Doc</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
:root {
--color: hsl(0, 0%, 65%);
}
* {
box-sizing: border-box;
}
body {
background: hsl(0, 0%, 16%);
font-family: sans-serif;
letter-spacing: 1.5px;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: center;
width: inherit;
height: inherit;
padding: 5rem;
font-size: 12px;
}
input {
border: none;
position: absolute;
margin: 6px 24px 8px 15px;
background: rgba(255, 255, 255, 0);
border-bottom: 1px solid var(--color);
outline: none;
}
.docExplorerWrap {
position: inherit;
width: 80%;
height: 100%;
top: 50%;
left: 50%;
background-color: hsl(0, 1%, 35%);
}
.doc-title, .doc-explore-content {
padding: 10px;
margin: 10px;
align-content: center;
border-bottom: 1px solid var(--color);
}
.doc-title {
display: flex;
}
.back {
width: 50px;
height: 50px;
}
h3, h4 {
font-weight: 300;
width: 100%;
margin: 15px;
}
h3 {
font-size: 1.25rem;
}
h4 {
font-size: 0.8rem;
white-space: pre;
}
b {
padding: 4px;
border-bottom: 1px solid var(--color);
}
a {
color:lightcoral;
}
a:hover {
text-decoration: underline;
cursor: pointer;
}
img {
cursor: pointer;
width: 30px;
height: 30px;
}
</style>
</head>
<body>
<script type="module" src="./lib/schema.js"></script>
<div class="docExplorerWrap">
<div class="doc-title"><h3 class="title">Schema Documentation</h3></div>
<div class="doc-explore-content">
<label class="search-box">
<img src="https://cdn1.iconfinder.com/data/icons/thin-ui-1/100/Noun_Project_100Icon_1px_grid_thin_ic_cookie-512.png">
<input class="search" type="text" placeholder="Search Schema...">
</label>
<div class="doc-type-description"> <h4 class="comment">A Graphql schema provides a root type for each kind of operation</h4><!-- description of... --></div>
<br>
<div class="doc-category"><h4><b class="doc-type">ROOT TYPES</b></h4></div>
<br>
<div class="display-doc"></h4></div>
</div>
</div>
</body>
</html>

157
subjects/graphql/lib/schema.js

@ -0,0 +1,157 @@
const backImg =
'https://cdn1.iconfinder.com/data/icons/thin-ui-1/100/Noun_Project_100Icon_1px_grid_thin_ic_arrow_left_simple-512.png'
const body = document.body
const main = document.querySelector('.doc-explore-content')
const docDisplay = document.querySelector('.display-doc')
const exist = () => document.querySelector('.back')
const removeComments = (obj) =>
Object.fromEntries(obj.filter((v) => v[0] !== 'comment'))
const getData = async (pathToFile) => {
const data = await fetch(pathToFile)
.then((data) => data.json())
.catch(console.log)
return data
}
const generateLinks = (k, v) => {
const h4 = document.createElement('h4')
const a = document.createElement('a')
a.innerText = v
h4.innerHTML = k
h4.appendChild(a)
docDisplay.appendChild(h4)
return a
}
const generateAllQueries = (data) => {
const docTitle = document.querySelector('.doc-title')
docDisplay.innerHTML = ''
const back = backArrow()
docTitle.appendChild(back)
for (let obj of data.types) {
for (const [k, _] of Object.entries(removeComments(Object.entries(obj)))) {
generateContent(k, obj)
}
}
}
const loadRootTypes = async () => {
const data = await getData('./lib/schema.json')
for (let v of data.root_types) {
const h4 = document.createElement('h4')
const a = document.createElement('a')
a.addEventListener('click', (event) => changeContent(event, data))
for (const [k, value] of Object.entries(v)) {
a.innerText = value
h4.innerHTML = `${k}: `
h4.appendChild(a)
docDisplay.appendChild(h4)
}
}
const a = generateLinks('all: ', 'all_available_queries')
a.addEventListener('click', () => generateAllQueries(data))
}
const generateContent = (t, data) => {
docDisplay.innerHTML += `type ${t.toUpperCase()} {`
for (const [k, v] of Object.entries(data[t])) {
generateLinks(` ${k}: `, v)
}
docDisplay.innerHTML += `}<br><br>`
for (let v of document.getElementsByTagName('a')) {
v.addEventListener('click', (e) => changeContent(e, data))
}
}
const backArrow = () => {
const title = document.querySelector('.title')
const typeDescription = document.querySelector('.comment')
const contType = document.querySelector('.doc-type')
const origType = contType.innerText
const origTitle = title.innerText
const origTypeDescription = typeDescription.innerText
const back = document.createElement('img')
back.className = 'back'
back.src = backImg
back.addEventListener('click', () => {
back.remove()
docDisplay.innerHTML = ''
title.innerText = origTitle
contType.innerText = origType
typeDescription.innerText = origTypeDescription
loadRootTypes()
})
return back
}
const allArgs = (data) => {
for (const [k, v] of Object.entries(data.arguments)) {
docDisplay.innerHTML += `<h4>${k}: <a>(${v.description})</a> // ${v.comment}</h4>`
}
}
const changeContent = ({ target }, data) => {
const title = document.querySelector('.title')
const typeDescription = document.querySelector('.comment')
const contType = document.querySelector('.doc-type')
const docTitle = document.querySelector('.doc-title')
const t = target.innerText
const back = backArrow()
title.innerText = t.toUpperCase()
contType.innerText = `${t.toUpperCase()} fields`
docDisplay.innerHTML = ''
if (/\[\w*\!\]\!/g.test(t)) {
const b = t.replace(/\[|\]|\!/g, '')
const obj = data.types.filter((v) => v[b])[0]
typeDescription.innerText = obj.comment
generateContent(b, obj)
} else if (t === 'arguments') {
allArgs(data)
!exist() && docTitle.appendChild(back)
} else {
generateContent(t, data)
!exist() && docTitle.appendChild(back)
}
}
loadRootTypes()
/* search */
const updateResult = (dataToSearch, { target }) => {
docDisplay.innerHTML = ''
dataToSearch.search.map((type) =>
target.value.split(' ').map((w) => {
if (type.toLowerCase().indexOf(w.toLowerCase()) !== -1) {
docDisplay.innerHTML += `<li><a class="query-result">${type}</a></li>`
document
.querySelectorAll('.query-result')
.forEach((ele) =>
ele.addEventListener('click', (e) => changeContent(e, dataToSearch))
)
}
})
)
}
const initSearch = async () => {
const data = await getData('./lib/schema.json')
const input = document.querySelector('.search')
input.addEventListener('focus', () => {
const bg = document.querySelector('.back')
if (!bg) {
const back = backArrow()
document.querySelector('.doc-title').appendChild(back)
}
docDisplay.innerHTML = ''
})
input.oninput = (e) => updateResult(data, e)
}
initSearch()
/*--------------*/

101
subjects/graphql/lib/schema.json

@ -0,0 +1,101 @@
{
"search": [
"[user!]!",
"[object!]!",
"[transaction!]!",
"[progress!]!",
"[result!]!",
"query",
"arguments"
],
"root_types": [{ "query": "query" }, { "arguments": "arguments" }],
"query": {
"user": "[user!]!",
"object": "[object!]!",
"transaction": "[transaction!]!",
"progress": "[progress!]!",
"result": "[result!]!"
},
"types": [
{
"user": {
"id": "ID!",
"attrs": "String!",
"createdAt": "String!",
"discordDMChannelId": "String!",
"discordId": "String!",
"discordLogin": "String!",
"githubId": "String!",
"githubLogin": "String!",
"profile": "String!",
"updatedAt": "String!"
},
"comment": "Fetch data from the table: \"user\""
},
{
"object": {
"id": "ID!",
"attrs": "String!",
"authorId": "String!",
"childrenAttrs": "String!",
"createdAt": "String!",
"externalRelationUrl": "String!",
"name": "String!",
"type": "String!",
"status": "String!",
"updatedAt": "String!"
},
"comment": "Fetch data from the table: \"object\""
},
{
"transaction": {
"id": "ID!",
"attrs": "String!",
"amount": "Int!",
"createdAt": "String!",
"type": "String!",
"userId": "Int!"
},
"comment": "Fetch data from the table: \"transaction\""
},
{
"progress": {
"id": "ID!",
"attrs": "String!",
"bestResultId": "Int!",
"createdAt": "String!",
"eventId": "Int!",
"groupId": "Int!",
"objectId": "Int!",
"updatedAt": "String!",
"userId": "Int!"
},
"comment": "Fetch data from the table: \"progress\""
},
{
"result": {
"id": "ID!",
"progressId": "Int!",
"attrs": "String!",
"createdAt": "String!",
"grade": "Int!",
"updatedAt": "String!"
},
"comment": "Fetch data from the table: \"result\""
}
],
"arguments": {
"where": {
"description": "bool_exp",
"comment": "filter the rows returned"
},
"order_by": {
"description": "[order_by!]",
"comment": "sort the rows by one or more columns"
},
"limit": {
"description": "Int",
"comment": "limit the number of rows returned"
}
}
}
Loading…
Cancel
Save