# V4 Components: Game Library Service

**URL:** <https://forum.vassalengine.org/t/v4-components-game-library-service/74733>\
**Category:** Development\
**Tags:** v4\
**Created:** [June 3, 2022, 10:46pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733 "2022-06-03T22:46:58Z")\
**Posts on this page:** 17\
**Page:** 2

<div class="post-metadata">

**Author:** ![uckelman](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/uckelman/32/10020_2.png) [@uckelman](https://forum.vassalengine.org/u/uckelman)\
**Post date:** [July 5, 2023, 10:24pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/21 "2023-07-05T22:24:17Z")

</div>

> [@Korval](#):
>
> Oh and a _critical_ addition module developer/maintainer.

We already have those. Maybe I’m not understanding what you’re saying here, because we’ve _always_ had those.

---

<div class="post-metadata">

**Author:** ![Korval](https://forum.vassalengine.org/letter_avatar_proxy/v4/letter/k/ecc23a/32.png) [@Korval](https://forum.vassalengine.org/u/Korval)\
**Post date:** [July 5, 2023, 10:30pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/22 "2023-07-05T22:30:38Z")

</div>

But we can’t search on them.

Which kind of bring up the point… What is the point of having the various data elements? Why are they important? What can we do with them?

---

<div class="post-metadata">

**Author:** ![uckelman](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/uckelman/32/10020_2.png) [@uckelman](https://forum.vassalengine.org/u/uckelman)\
**Post date:** [July 5, 2023, 10:34pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/23 "2023-07-05T22:34:02Z")

</div>

> [@Korval](#):
>
> But we can’t search on them

You can. Why do you think you can’t?

> [@Korval](#):
>
> What is the point of having the various data elements? Why are they important? What can we do with them?

All of this metadata will be available through the library API. So… you could do anything you want with it, but only if the fields you want are present. The use I intend to put it to first is generating all the module pages on the site.

---

<div class="post-metadata">

**Author:** ![uckelman](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/uckelman/32/10020_2.png) [@uckelman](https://forum.vassalengine.org/u/uckelman)\
**Post date:** [July 5, 2023, 11:17pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/24 "2023-07-05T23:17:12Z")

</div>

Formatted as TOML, you might have this:

```auto
[game]
title = "Paths of Glory"
publisher = "GMT Games"
year = 1999
number_of_players = 2
tags = ["WWI", "strategic", "card driven", "point to point"]

```

I’ve collapsed all of the tag-like fields in to `tags`. I’m not convinced that `length` is a field we should keep. Maybe we should have the endpoints of the player range represented individually (though it would make it impossible to represent the allowed numbers of players for any oddball games which have gaps in their ranges…).

We should probably have a `title_sortkey` field, for handling titles that do not sort strictly alphabetically (e.g., anything starting with “A”, “An”, “The”).

---

<div class="post-metadata">

**Author:** ![Korval](https://forum.vassalengine.org/letter_avatar_proxy/v4/letter/k/ecc23a/32.png) [@Korval](https://forum.vassalengine.org/u/Korval)\
**Post date:** [July 6, 2023, 12:22pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/25 "2023-07-06T12:22:32Z")

</div>

> [@uckelman](#):
>
> > [@Korval](#):
> >
> > But we can’t search on them
> 
> You can. Why do you think you can’t?

If I go to the Modules section of the website, there is no generic (or advanced) search option. Instead, you have the ability to sort by a limited # of options - Number of Players, Publisher, Game Series, etc.

So if I wanted to say search on the following 2 examples, I can’t…

1. Module Maintainer = Korval
2. Game Designer = Craig Besinque AND Era = WW2

(these btw are both real examples I have wanted in the current system)

Having more sort options would be great, but having a search capability for modules would also be great. That seems to be where we are heading for V4…

---

<div class="post-metadata">

**Author:** ![uckelman](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/uckelman/32/10020_2.png) [@uckelman](https://forum.vassalengine.org/u/uckelman)\
**Post date:** [July 6, 2023, 12:26pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/26 "2023-07-06T12:26:21Z")

</div>

> [@Korval](#):
>
> So if I wanted to say search on the following 2 examples, I can’t…
> 
> 1. Module Maintainer = Korval
> 2. Game Designer = Craig Besinque AND Era = WW2

You can do 1 with the search function in the wiki:

[https://vassalengine.org/w/index.php?search=Korval&title=Special%3ASearch&profile=default&fulltext=1](https://vassalengine.org/w/index.php?search=Korval&title=Special%3ASearch&profile=default&fulltext=1)

You can do 2 similarly, but you won’t get any results because game designers aren’t listed presently.

---

<div class="post-metadata">

**Author:** ![uckelman](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/uckelman/32/10020_2.png) [@uckelman](https://forum.vassalengine.org/u/uckelman)\
**Post date:** [July 6, 2023, 11:22pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/27 "2023-07-06T23:22:20Z")

</div>

Some fields which are specific to modules, not to games:

For a particular module file:

- name
- version
- authors
- required Vassal version
- description

(I’m not including size here because that’s not something you set, but is rather a property derived from the file.)

For all the versions of a module collectively:

- notes
- repository URL
- homepage URL

I’m envisioning some of these as optional.

---

<div class="post-metadata">

**Author:** ![pawnpusher](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/pawnpusher/32/184_2.png) [@pawnpusher](https://forum.vassalengine.org/u/pawnpusher)\
**Post date:** [July 7, 2023, 1:40am UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/28 "2023-07-07T01:40:14Z")

</div>

> [@uckelman](#):
>
> > [@Korval](#):
> >
> > So if I wanted to say search on the following 2 examples, I can’t…
> > 
> > 1. Module Maintainer = Korval
> > 2. Game Designer = Craig Besinque AND Era = WW2
> 
> You can do 1 with the search function in the wiki:
> 
> [https://vassalengine.org/w/index.php?search=Korval&title=Special%3ASearch&profile=default&fulltext=1](https://vassalengine.org/w/index.php?search=Korval&title=Special%3ASearch&profile=default&fulltext=1)
> 
> You can do 2 similarly, but you won’t get any results because game designers aren’t listed presently.

Wow!! I would never have guessed that, nor would I have a clue where to start looking to see how to do it.

---

<div class="post-metadata">

**Author:** ![Brent\_Easton](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/brent_easton/32/10_2.png) [@Brent\_Easton](https://forum.vassalengine.org/u/Brent_Easton)\
**Post date:** [July 7, 2023, 4:24am UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/29 "2023-07-07T04:24:47Z")

</div>

> [@uckelman](#):
>
> You can do 1 with the search function in the wiki:
> 
> [Search results for "Korval" - Vassal](https://vassalengine.org/w/index.php?search=Korval&title=Special%3ASearch&profile=default&fulltext=1)

Not really, that returns any module page that contains the text ‘Korval’, whether that is maintainer, contributor or Player, or the module ‘Korval at War’. You get there in the end, but it’s not really a maintainer search as such.

We will want any metatdata we define to be individually searchable.

> I’ve collapsed all of the tag-like fields in to `tags`.

I have no problem in collapsing all the tags into one list, as long as it is easy to view and select from the existing tags in a logical way when you are registering the modile. IMO, having ‘mechanism’ and ‘category’ tags mixed in together makes it more difficult to find what you are looking for. However. Module registration is a relatively infrequent process, so maybe that isn’t such an issue.

---

<div class="post-metadata">

**Author:** ![uckelman](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/uckelman/32/10020_2.png) [@uckelman](https://forum.vassalengine.org/u/uckelman)\
**Post date:** [July 7, 2023, 10:20am UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/30 "2023-07-07T10:20:40Z")

</div>

> [@pawnpusher](#):
>
> Wow!! I would never have guessed that, nor would I have a clue where to start looking to see how to do it.

The search field is available from the hamburger menu in the upper right.

---

<div class="post-metadata">

**Author:** ![Tim\_M](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/tim_m/32/2_2.png) [@Tim\_M](https://forum.vassalengine.org/u/Tim_M)\
**Post date:** [July 8, 2023, 12:30am UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/31 "2023-07-08T00:30:15Z")

</div>

From a Library perspective I would love to be able to have multiple tags within our defined classes. Some games are made by publisher A - reimplemented by publisher B etc…  
BGG does this, unfortunately we cannot at this time.

It leads back to the original website chaos of X number of pages for the same game because module designers feel their module is different because of who actually published the game or their take on design

I know my thoughts here are kind of a side track to the meta data capture for V4 modules in future, but it is (and should be) part and parcel with our site at same time…

Everyone has very valid points to consider imo - Its a difficult problem to solve

---

<div class="post-metadata">

**Author:** ![uckelman](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/uckelman/32/10020_2.png) [@uckelman](https://forum.vassalengine.org/u/uckelman)\
**Post date:** [August 17, 2023, 11:01pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/32 "2023-08-17T23:01:20Z")

</div>

Below I will post a sketch of a Game Library Service API. Not everything is filled in yet. Comments welcome.

---

<div class="post-metadata">

**Author:** ![uckelman](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/uckelman/32/10020_2.png) [@uckelman](https://forum.vassalengine.org/u/uckelman)\
**Post date:** [August 17, 2023, 11:03pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/33 "2023-08-17T23:03:24Z")

</div>

# Module Library API Reference (Draft)

## Reference

All paths relative to `/api/v1`.

- `/projects` [`GET`](#heading--get-projects)
  - `/{proj_id}` [`GET`](#heading--get-projects-proj_id) [`PUT`](#heading--put-projects-proj_id)
    - `/{revision}` [`GET`](#heading--get-projects-proj_id-revision)
    - `/owners` [`GET`](#heading--get-projects-proj_id-owners) [`PUT`](#heading--put-projects-proj_id-owners) [`DELETE`](#heading--delete-projects-proj_id-owners)
    - `/players` [`GET`](#heading--get-projects-proj_id-players) [`PUT`](#heading--put-projects-proj_id-players) [`DELETE`](#heading--delete-projects-proj_id-players)
    - `/packages`
      - `/{pkg_name}` [`GET`](#heading--get-projects-proj_id-packages-pkg_name)
        - `/{version}` [`GET`](#heading--get-projects-proj_id-packages-pkg_name-version) [`PUT`](#heading--put-projects-proj_id-packages-pkg_name-version)

    - `/readme` [`GET`](#heading--get-projects-proj_id-readme)
      - `/{revision}` [`GET`](#heading--get-projects-proj_id-readme-revision)

    - `/images`
      - `/{img_name}` [`GET`](#heading--get-projects-proj_id-images-img_name) [`PUT`](#heading--get-projects-proj_id-images-img_name)

- `/games` [`GET`](#heading--get-games)
- `/tags` [`GET`](#heading--get-tags)
- `/users` [`GET`](#heading--get-users)
- `/login` [`POST`](#heading--post-login)

## Description

#### `GET /projects`

Get a list of projects.

##### Parameters

- `q` Limit results to projects containing the query term.
- `tag` Limit results to projects so tagged.
- `prefix` Limit results to projects starting with the given prefix.
- `owner` Limit results to projects having the given owner.
- `seek` Key for pagination.

##### Returns

```json
{
  "projects": [
    { },
    ...
  ],
  "meta": {
    "prev_page": "",
    "next_page": "",
    "total": 1234
  }
}

```

#### `GET /projects/{proj_id}`

Get current metadata for project `proj_id`.

##### Returns

```json
{
  "id": "",
  "name": "",
  "description": "",
  "revision": 2,
  "created_at": "2023-08-12T17:10:29.188970+00:00",
  "modified_at": "2023-08-13T23:54:10.578320+00:00",
  "modified_by": "",
  "tags": [],
  "readme_path": "",
  "game": {
    "title": "",
    "title_sort_key": "",
    "publisher": "",
    "year": ""
  },
  "owners": ["alice", "bob"],
  "packages": [
    {
      "id": "",
      "name": "",
      "description": ""
      "versions": [
        {
          "number": "1.2.3",
          "dl_path": "",
          "type": "",
          "checksum": "",
          "size": 123456,
          "published_at": "2023-08-13T23:54:10.578320+00:00",
          "published_by": "",
          "requires": "",
          "authors": ["alice", "bob"]
        }
      ]
    }
  ]
}

```

#### `PUT /projects/{proj_id}`

Update metadata for project `proj_id`. Creates project `proj_id` if it does not yet exist.

Requires auth token. Logged in user must be in the owners list for a preexisting project.

##### Payload

```json
{
  // TBD
}

```

##### Returns

```json
{
  // TBD
}

```

#### `GET /projects/{proj_id}/{revision}`

Get metadata for project `proj_id` at `revision`.

##### Returns

See [`GET /projects/{proj_id}`](#heading--get-projects-proj_id) for the return format.

#### `GET /projects/{proj_id}/owners`

Get the list of owners for project `proj_id`.

##### Returns

```json
{
  "users": ["alice", "bob"]
}

```

#### `PUT /projects/{proj_id}/owners`

Add owners for project `proj_id`.

Requires auth token. Logged in user must be in the owners list.

##### Payload

```json
{
  "users": ["alice", "bob"] 
}

```

#### `DELETE /projects/{proj_id}/owners`

Remove owners from project `proj_id`.

Requires auth token. Logged in user must be in the owners list.

##### Payload

```json
{
  "users": ["alice", "bob"] 
}

```

#### `GET /projects/{proj_id}/players`

Get the list of players for project `proj_id`.

##### Returns

```json
{
  "users": ["alice", "bob"]
}

```

#### `PUT /projects/{proj_id}/players`

Add player for project `proj_id`.

Requires auth token. Logged in user must be the player to add.

##### Payload

```json
{
  "user": "alice" 
}

```

#### `DELETE /projects/{proj_id}/players`

Remove player from project `proj_id`.

Requires auth token. Logged in user must be the player to remove.

##### Payload

```json
{
  "user": "alice" 
}

```

#### `GET /projects/{proj_id}/packages/{pkg_name}`

Download current version of `pkg_name`. May be a redirect.

#### `GET /projects/{proj_id}/packages/{pkg_name}/{version}`

Download `version` of `pkg_name`. May be a redirect.

#### `PUT /projects/{proj_id}/packages/{pkg_name}/{version}`

Publish `version` of `pkg_name`. Fails if `version` already exists.

Requires auth token. Logged in user must be in the owners list.

##### Payload

```json
{
   // TBD
}

```

#### `GET /projects/{proj_id}/readme`

Get the project readme for the current revision of `proj_id`. The readme is formatted as Markdown.

#### `GET /projects/{proj_id}/readme/{revision}`

Get the project readme for revision `revision` of `proj_id`. The readme is formatted as Markdown.

#### `GET /projects/{proj_id}/images/{img_name}`

#### `PUT /projects/{proj_id}/images/{img_name}`

Requires auth token. Logged in user must be in the owners list.

#### `GET /tags`

##### Parameters

- `prefix`

##### Returns

```json
{
  // TBD
}

```

#### `GET /games`

##### Parameters

- `prefix`

##### Returns

```json
{
  // TBD
}

```

#### `GET /tags`

##### Parameters

- `prefix`

##### Returns

```json
{
  // TBD
}

```

#### `POST /login`

Log in. (Possibly this should not be here, but in a user management service instead.)

##### Payload

```json
{
  "username": "skroob",
  "passwrod": "12345"
}

```

##### Returns

```json
{
  "token": "abcdefg..."
}

```

The token must be sent in an `Authorization` header for any requests requiring authroization:

```auto
Authorization: Bearer abcdefg...

```

#### `GET /users`

Get list of users. (This is needed by any frontend which will do autocomplete. Possibly this should not be here, but in a user management service instead.) Should support pagination.

Requires auth token.

##### Parameters

- `prefix`

##### Returns

```json
{
  "users": ["alice", "bob"]
}

```

---

<div class="post-metadata">

**Author:** ![Brent\_Easton](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/brent_easton/32/10_2.png) [@Brent\_Easton](https://forum.vassalengine.org/u/Brent_Easton)\
**Post date:** [August 21, 2023, 12:56am UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/34 "2023-08-21T00:56:25Z")

</div>

Looking good.

It will be good to lock in some sensible terminology as we go along.

So, my read is that a `Project` is roughly equivalent to a what we see in a Module Page currently. A `Package` is an individually versioned sub-component of the `Project`.

I’m guessing these will be individual files like the ‘Module’ (whatever that ends up being), version history and other associated documentation. An older LTS version of the `Project` main module might be stored as a separate `Package` while a newer version is being developed.

Do we want to keep using `Module` to refer to the thing that contains the game implementation? It’s a good word, I like it.

What are `games`? Is that a list of Games that the `Project` is implementing? Thoughts on how we maintain a unique list of these? I would suggest BGG game Id’s? Their TOS allow us to harvest their game DB for this sort of thing, no point in re-inventing the wheel. We can potentially do Ajax-style auto-complete lookups on game names etc.

---

<div class="post-metadata">

**Author:** ![Korval](https://forum.vassalengine.org/letter_avatar_proxy/v4/letter/k/ecc23a/32.png) [@Korval](https://forum.vassalengine.org/u/Korval)\
**Post date:** [August 22, 2023, 10:37am UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/35 "2023-08-22T10:37:08Z")

</div>

A couple of comments:

1. I like the term “module.” (One huge beef I have w/ Microsoft is how they keep changing the UI… (usually dumbing it down))

2. Suggest add “game\_designer” as a tag

3. Probably out of scope for this discussion, but suggest consider 2-factor authentication for module/library actions (add, modify, delete). A common commercial paradigm is to send a security code to your registered email…

---

<div class="post-metadata">

**Author:** ![beckerdo](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/beckerdo/32/7549_2.png) [@beckerdo](https://forum.vassalengine.org/u/beckerdo)\
**Post date:** [August 22, 2023, 8:33pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/36 "2023-08-22T20:33:07Z")

</div>

My comment on the game library service is that it is a great start to something that will really help VASSAL.

One design comment is to consider providing some useful links in the reply body that will save the client and the server from repeatedly accessing related information.

For example, a client accesses the projects endpoint which provides 5 owners and 50 players. Now the client assembles a request to access the 5 users and another request to get the 50 players. Also the notification requires some game information, so another request to the games or tags end point.

Obviously, getting all this information requires work from the client and the server and there is a balance somewhere in between too much client work, too much server work, and too much information over the wire. However sometimes, the information is easily available on the server side and much quicker than multiple requests/responses and encodes/decodes.

Another way to look at this is “how many useful next-step links do you want to provide the consumer”? This idea is part of the idea of a RESTful service, which might help generate more clients or might be too much.

Just food for thought. This web interface as-is is a major step-up in VASSAL customer service.

---

<div class="post-metadata">

**Author:** ![uckelman](https://forum.vassalengine.org/user_avatar/forum.vassalengine.org/uckelman/32/10020_2.png) [@uckelman](https://forum.vassalengine.org/u/uckelman)\
**Post date:** [February 27, 2024, 1:41pm UTC](https://forum.vassalengine.org/t/v4-components-game-library-service/74733/37 "2024-02-27T13:41:43Z")

</div>

We’ve made significant progress on the GLS component since I started working on it seriously in October. There’s a nearly usable prototype here:

> **[GitHub - vassalengine/game-library-service](https://github.com/vassalengine/game-library-service)**
>
> Contribute to vassalengine/game-library-service development by creating an account on GitHub.

The short-term goal is to use the GLS to replace the current game library in the wiki. To that end, I’ve concurrently been working on a new game library frontend which uses the GLS:

> **[GitHub - vassalengine/game-library-frontend](https://github.com/vassalengine/game-library-frontend)**
>
> Contribute to vassalengine/game-library-frontend development by creating an account on GitHub.

I am aiming for these to be ready for use in March, but that is an aspiration, not a promise.

[Previous page](https://forum.vassalengine.org/t/v4-components-game-library-service/74733.md?page=1)
