Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 71 additions & 52 deletions backend/backend-api.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Backend-API

## Queries

### game

Henter informasjon om ett enkelt spill ved ID.
Expand All @@ -25,7 +27,9 @@ game(id: ID!): Game
game(id: "3498") {
name
esrbRating
genres { name }
genres {
name
}
}
}
```
Expand Down Expand Up @@ -54,11 +58,11 @@ games(search: String, filter: GameFilter, first: Int = 20): GameConnection!

#### Argumenter

| Navn | Type | Default | Beskrivelse |
| -------- | --------------------------- | ------- | --------------------------------------------------------------------------------------------- |
| Navn | Type | Default | Beskrivelse |
| -------- | --------------------------- | ------- | --------------------------------------------------------------------------------------------------------- |
| `search` | `String` | — | Søk i tittel og alternative navn. Skiller ikke mellom store og små bokstaver, og matcher deler av navnet. |
| `filter` | [`GameFilter`](#gamefilter) | — | Filtrering på sjanger, plattform og utgivelsesår. |
| `first` | `Int` | `20` | Antall spill på siden. Begrenset til 1–50. |
| `filter` | [`GameFilter`](#gamefilter) | — | Filtrering på sjanger, plattform og utgivelsesår. |
| `first` | `Int` | `20` | Antall spill på siden. Begrenset til 1–50. |

Alle argumenter er valgfrie og kan kombineres.

Expand All @@ -72,7 +76,11 @@ Alle argumenter er valgfrie og kan kombineres.
{
games(search: "zelda", first: 3) {
totalCount
edges { node { name } }
edges {
node {
name
}
}
}
}
```
Expand Down Expand Up @@ -103,7 +111,12 @@ Action- og RPG-spill på PC, utgitt 2015–2020:
first: 3
) {
totalCount
edges { node { name released } }
edges {
node {
name
released
}
}
}
}
```
Expand Down Expand Up @@ -145,7 +158,10 @@ Liste med [`Facet`](#facet).

```graphql
{
genres { id name }
genres {
id
name
}
}
```

Expand Down Expand Up @@ -185,7 +201,10 @@ Merk: ID-ene her er plattformfamilier og er ikke de samme som ID-ene i `Game.pla

```graphql
{
platforms { id name }
platforms {
id
name
}
}
```

Expand All @@ -202,36 +221,38 @@ Merk: ID-ene her er plattformfamilier og er ikke de samme som ID-ene i `Game.pla
```

## Mutations

> Dette skal legges til når funksjonalitet for brukere blir lagt til
## Types

### Game

Et spill med detaljer og relasjoner.

| Felt | Type | Beskrivelse |
| --------------------------- | ------------------- | ----------------------------------------------------------------- |
| `id` | `ID!` | ID til spillet. |
| `name` | `String!` | Tittel. |
| `description` | `String` | Beskrivelse i ren tekst. |
| `released` | `String` | Utgivelsesdato, `YYYY-MM-DD`. |
| `website` | `String` | Offisiell nettside. |
| `added` | `Int!` | Antall RAWG-brukere som har lagt spillet til i en liste. Brukes som mål på popularitet. |
| `metacritic` | `Int` | Metacritic-score, 0–100. |
| `rating` | `Float` | RAWG-brukernes snittvurdering, 0–5. |
| `ratingsCount` | `Int!` | Antall vurderinger bak `rating`. |
| `playtime` | `Int` | Gjennomsnittlig spilletid i timer. |
| `esrbRating` | `String` | Amerikansk aldersgrense, f.eks. `Mature`. |
| `dominantColor` | `String` | Hovedfargen i forsidebildet som hex, f.eks. `0f0f0f`. |
| `backgroundImage` | `String` | URL til forsidebildet. |
| `backgroundImageAdditional` | `String` | URL til et ekstra bilde. |
| `screenshots` | `[String!]!` | URL-er til skjermbilder. Tom liste hvis ingen. |
| `genres` | [`[Facet!]!`](#facet) | Sjangre. |
| `platforms` | [`[Facet!]!`](#facet) | Enkeltkonsoller, f.eks. PlayStation 4. |
| `stores` | [`[Facet!]!`](#facet) | Butikker spillet selges i. |
| `developers` | [`[Facet!]!`](#facet) | Utviklere. |
| `publishers` | [`[Facet!]!`](#facet) | Utgivere. |
| `tags` | [`[Facet!]!`](#facet) | Tagger fra RAWG, f.eks. Open World. |
| Felt | Type | Beskrivelse |
| --------------------------- | --------------------- | --------------------------------------------------------------------------------------- |
| `id` | `ID!` | ID til spillet. |
| `name` | `String!` | Tittel. |
| `description` | `String` | Beskrivelse i ren tekst. |
| `released` | `String` | Utgivelsesdato, `YYYY-MM-DD`. |
| `website` | `String` | Offisiell nettside. |
| `added` | `Int!` | Antall RAWG-brukere som har lagt spillet til i en liste. Brukes som mål på popularitet. |
| `metacritic` | `Int` | Metacritic-score, 0–100. |
| `rating` | `Float` | RAWG-brukernes snittvurdering, 0–5. |
| `ratingsCount` | `Int!` | Antall vurderinger bak `rating`. |
| `playtime` | `Int` | Gjennomsnittlig spilletid i timer. |
| `esrbRating` | `String` | Amerikansk aldersgrense, f.eks. `Mature`. |
| `dominantColor` | `String` | Hovedfargen i forsidebildet som hex, f.eks. `0f0f0f`. |
| `backgroundImage` | `String` | URL til forsidebildet. |
| `backgroundImageAdditional` | `String` | URL til et ekstra bilde. |
| `screenshots` | `[String!]!` | URL-er til skjermbilder. Tom liste hvis ingen. |
| `genres` | [`[Facet!]!`](#facet) | Sjangre. |
| `platforms` | [`[Facet!]!`](#facet) | Enkeltkonsoller, f.eks. PlayStation 4. |
| `stores` | [`[Facet!]!`](#facet) | Butikker spillet selges i. |
| `developers` | [`[Facet!]!`](#facet) | Utviklere. |
| `publishers` | [`[Facet!]!`](#facet) | Utgivere. |
| `tags` | [`[Facet!]!`](#facet) | Tagger fra RAWG, f.eks. Open World. |

Relasjonene returnerer en tom liste hvis spillet ikke har noen.

Expand All @@ -252,30 +273,30 @@ Felles type for sjangre, plattformer, butikker, utviklere, utgivere og tagger.

Resultatet av [`games`](#games). Følger Relay-mønsteret for paginering (se [dokumentasjon](https://graphql.org/learn/pagination/)).

| Felt | Type | Beskrivelse |
| ------------ | --------------------------- | --------------------------------------------------- |
| `edges` | [`[GameEdge!]!`](#gameedge) | Spillene på denne siden. |
| `pageInfo` | [`PageInfo!`](#pageinfo) | Informasjon for å hente neste side. |
| `totalCount` | `Int!` | Totalt antall spill som matcher søk og filtre. |
| Felt | Type | Beskrivelse |
| ------------ | --------------------------- | ---------------------------------------------- |
| `edges` | [`[GameEdge!]!`](#gameedge) | Spillene på denne siden. |
| `pageInfo` | [`PageInfo!`](#pageinfo) | Informasjon for å hente neste side. |
| `totalCount` | `Int!` | Totalt antall spill som matcher søk og filtre. |

---

### GameEdge

Ett spill i en [`GameConnection`](#gameconnection).

| Felt | Type | Beskrivelse |
| -------- | -------------------- | ------------------------------------ |
| `node` | [`Game!`](#game-1) | Spillet. |
| `cursor` | `String!` | Posisjonen til spillet i listen. |
| Felt | Type | Beskrivelse |
| -------- | ------------------ | -------------------------------- |
| `node` | [`Game!`](#game-1) | Spillet. |
| `cursor` | `String!` | Posisjonen til spillet i listen. |

---

### PageInfo

| Felt | Type | Beskrivelse |
| ------------- | ---------- | ------------------------------------------------------------- |
| `hasNextPage` | `Boolean!` | `true` hvis det finnes flere spill etter denne siden. |
| Felt | Type | Beskrivelse |
| ------------- | ---------- | ------------------------------------------------------------------- |
| `hasNextPage` | `Boolean!` | `true` hvis det finnes flere spill etter denne siden. |
| `endCursor` | `String` | Cursor til siste spill på siden. Sendes som `after` for neste side. |

---
Expand All @@ -284,13 +305,11 @@ Ett spill i en [`GameConnection`](#gameconnection).

Input-type for filtrering i [`games`](#games). Alle felt er valgfrie.

| Felt | Type | Beskrivelse |
| -------------- | -------- | ------------------------------------------------------------------------------ |
| `genreIds` | `[ID!]` | Spill som har **alle** de valgte sjangrene. ID-er fra [`genres`](#genres). |
| `platformIds` | `[ID!]` | Spill på **minst én** av de valgte plattformfamiliene. ID-er fra [`platforms`](#platforms). |
| `releasedFrom` | `Int` | Utgitt dette året eller senere, f.eks. `2015`. |
| `releasedTo` | `Int` | Utgitt dette året eller tidligere, f.eks. `2020`. |
| Felt | Type | Beskrivelse |
| -------------- | ------- | ------------------------------------------------------------------------------------------- |
| `genreIds` | `[ID!]` | Spill som har **alle** de valgte sjangrene. ID-er fra [`genres`](#genres). |
| `platformIds` | `[ID!]` | Spill på **minst én** av de valgte plattformfamiliene. ID-er fra [`platforms`](#platforms). |
| `releasedFrom` | `Int` | Utgitt dette året eller senere, f.eks. `2015`. |
| `releasedTo` | `Int` | Utgitt dette året eller tidligere, f.eks. `2020`. |

Merk: Spill uten utgivelsesdato utelates når `releasedFrom` eller `releasedTo` er satt. ID-er som ikke er tall ignoreres.


4 changes: 3 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"start": "pnpm run build && node dist/index.js",
"lint": "eslint ."
},
"files": ["dist"],
"files": [
"dist"
],
"keywords": [],
"author": "",
"license": "ISC",
Expand Down
3 changes: 1 addition & 2 deletions backend/src/auth.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@

// server jwt secret
// const secret = process.env.JWT_SECRET;
// const secret = process.env.JWT_SECRET;
4 changes: 2 additions & 2 deletions backend/src/db.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pg from 'pg';

const url = process.env.DATABASE_URL;
if (!url) throw new Error("DATABASE_URL not set in .env ...")
if (!url) throw new Error('DATABASE_URL not set in .env ...');

//pg pool
export const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL})
export const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
12 changes: 6 additions & 6 deletions backend/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { pool } from './db.js';
import { typeDefs } from './schema.js';
import { resolvers } from './resolvers.js';

// apollo-server port number [default port 3001]
const port = Number(process.env.PORT ?? 3001)
// apollo-server port number [default port 3001]
const port = Number(process.env.PORT ?? 3001);

// tester db tilkobling med en query
await pool.query('SELECT 1');
Expand All @@ -15,7 +15,7 @@ const server = new ApolloServer({ typeDefs, resolvers });

// pass apolloserver to standaloneserver
const { url } = await startStandaloneServer(server, {
listen: { port },
listen: { port },
});

console.log(`Server ready at: ${url}`);
console.log(`Server ready at: ${url}`);
36 changes: 18 additions & 18 deletions backend/src/resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { assertName } from 'graphql';
import { pool } from './db.js';

// type definitions
Expand All @@ -13,12 +12,12 @@ type GameFilter = {
platformIds?: string[] | null;
releasedFrom?: number | null;
releasedTo?: number | null;
}
};

// const vars and func
const VALID_ID_REGEX = /^\d{1,18}$/;
const MAX_PAGE_SIZE = 50;
const escapeChars = (s: string) => s.replace(/[\\%_]/g, '\\$&')
const escapeChars = (s: string) => s.replace(/[\\%_]/g, '\\$&');

// definerer hvilke kolonner som skal hentes for en generell
// forespørsel om et spill, inkludert oversetting fra databasen
Expand Down Expand Up @@ -74,7 +73,6 @@ const GAMES_WHERE = `
AND ${WHERE_RELEASED_TO}
`;


// SQL queries
const SQL_COUNT = `
SELECT count(*)::int AS count FROM games
Expand All @@ -101,18 +99,18 @@ const SQL_GAMES = `

// hjelpefunksjoner
function toIds(ids?: string[] | null) {
const nums = (ids??[]).map(Number).filter(Number.isInteger);
return nums.length? nums : null;
const nums = (ids ?? []).map(Number).filter(Number.isInteger);
return nums.length ? nums : null;
}
// returnerer array med filter-verdiene
function filterValues(args: GamesArgs) {
const term = args.search?.trim();
return [
term? `%${escapeChars(term)}%` : null,
term ? `%${escapeChars(term)}%` : null,
toIds(args.filter?.genreIds),
toIds(args.filter?.platformIds),
args.filter?.releasedFrom??null,
args.filter?.releasedTo??null,
args.filter?.releasedFrom ?? null,
args.filter?.releasedTo ?? null,
];
}
// resolver for koblings-tabellene i databasen
Expand All @@ -124,27 +122,29 @@ function relation(table: string, junc: string, fk: string) {
WHERE j.game_id = $1
ORDER BY t.name
`;
return async (game: {id: string }) => {
return async (game: { id: string }) => {
const res = await pool.query(sql, [game.id]);
return res.rows;
};
};
}

// resolver-funksjoner
async function game(_parent: unknown, args: { id: string }) {
if (!VALID_ID_REGEX.test(args.id)) { return null; }
const res = await pool.query(SQL_GAME, [args.id])
if (!VALID_ID_REGEX.test(args.id)) {
return null;
}
const res = await pool.query(SQL_GAME, [args.id]);
return res.rows[0] ?? null;
};
}

async function games(_parent: unknown, args: GamesArgs ) {
async function games(_parent: unknown, args: GamesArgs) {
const values = filterValues(args);
const first = Math.min(Math.max(args.first, 1), MAX_PAGE_SIZE);
const first = Math.min(Math.max(args.first, 1), MAX_PAGE_SIZE);

const res = await pool.query(SQL_GAMES, [...values, first]);
return {
edges: res.rows.map((row) => ({ node: row, cursor: '' })),
pageInfo: { hasNextPage: false, endCursor: null},
pageInfo: { hasNextPage: false, endCursor: null },
values,
};
}
Expand Down Expand Up @@ -174,5 +174,5 @@ export const resolvers = {
tags: relation('tags', 'game_tags', 'tag_id'),
},

GameConnection: { totalCount }
GameConnection: { totalCount },
};
3 changes: 1 addition & 2 deletions backend/src/schema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

export const typeDefs = `#graphql
"""
Definerer input argumentene som er gyldige mot serveren.
Expand Down Expand Up @@ -83,4 +82,4 @@ export const typeDefs = `#graphql
genres: [Facet!]!
platforms: [Facet!]!
}
`;
`;
Loading