Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSON Schema #106

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ node_modules
/coverage
/vendor/
composer.phar
/.idea
/.idea
.aider*
.env
161 changes: 161 additions & 0 deletions schema/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Meeting Guide API Schemas

## Overview

This directory contains JSON schemas used for validating meeting data structures in the Meeting Guide API. These schemas are designed to ensure data consistency and integrity for applications that manage meeting information. These schemas are based on the JSON Schema Draft-07 specification.

### Schemas Included

1. **meeting.schema.json**
- **Description**: Defines the structure for individual meeting entries, including details such as name, location, time, and contact information. Only `name` and `slug` are required but additional properties should be used when possible.
- **Key Properties**:

| Property | Description | Type |
|------------------------|-----------------------------------------------------------------------------------------------|---------------|
| `name` | The name of the meeting, max 64 characters. | string |
| `slug` | A unique identifier for the meeting, used as the primary key, max 255 characters. | string |
| `day` | The day(s) of the week the meeting occurs (integer or array of integers 0-6). | integer/array of integers |
| `time` | The start time of the meeting in HH:MM 24-hour format. | string |
| `end_time` | The optional end time of the meeting in HH:MM 24-hour format. | string |
| `timezone` | The optional timezone of the meeting in tz database format. | string |
| `formatted_address` | The complete address of the meeting location. | string |
| `address` | The street address of the meeting location. | string |
| `city` | The city where the meeting is held. | string |
| `state` | The state where the meeting is held, 2 uppercase letters. | string |
| `postal_code` | The postal code of the meeting location, 5 digits. | string |
| `country` | The country where the meeting is held. | string |
| `region` | An optional geographical subset of meeting locations. | string |
| `sub_region` | An optional further specification of the region. | string |
| `regions` | A hierarchical array of regions, from general to specific. | array of strings |
| `conference_url` | The URL for an online meeting, URI format. | string |
| `conference_url_notes` | Optional metadata about the conference URL. | string |
| `conference_phone` | The phone number for dialing into an online meeting. | string |
| `conference_phone_notes`| Optional metadata about the conference phone number. | string |
| `types` | An optional array of standardized meeting types. | array of strings |
| `notes` | Optional additional details about the meeting. | string |
| `location` | The name of the building or landmark where the meeting is held. | string |
| `location_notes` | Optional notes applicable to all meetings at the location. | string |
| `latitude` | The optional latitude of the meeting location. | number |
| `longitude` | The optional longitude of the meeting location. | number |
| `approximate` | Indicates if the address is approximate ("yes" or "no"). | string |
| `updated` | The optional timestamp indicating when the listing was last updated, in YYYY-MM-DD HH:MM:SS format. | string |
| `group` | The optional name of the group providing the meeting. | string |
| `group_notes` | Optional group-related notes. | string |
| `venmo` | The optional Venmo handle for contributions. | string |
| `square` | The optional Square Cash App cashtag for contributions. | string |
| `paypal` | The optional PayPal.me username for contributions. | string |
| `url` | The optional URL pointing to the meeting's listing on the area website, URI format. | string |
| `edit_url` | The optional URL that trusted servants can use to edit the meeting's listing, URI format. | string |
| `feedback_emails` | An optional array of feedback email addresses for the service entity. | array of strings |
| `feedback_url` | The optional URL for providing feedback about the meeting, URI format. | string |
| `entity` | The name of the service entity responsible for the listing. | string |
| `entity_email` | The public email address for the service entity, email format. | string |
| `entity_location` | A description of the service area of the entity. | string |
| `entity_logo` | The URL of the logo of the service entity, URI format. | string |
| `entity_phone` | The phone number of the service entity. | string |
| `entity_website_url` | The website homepage of the service entity, URI format. | string |
| `contact_1_name` | The name of the first contact person for the meeting. | string |
| `contact_1_email` | The email address of the first contact person, email format. | string |
| `contact_1_phone` | The phone number of the first contact person. | string |
| `contact_2_name` | The name of the second contact person for the meeting. | string |
| `contact_2_email` | The email address of the second contact person, email format. | string |
| `contact_2_phone` | The phone number of the second contact person. | string |
| `contact_3_name` | The name of the third contact person for the meeting. | string |
| `contact_3_email` | The email address of the third contact person, email format. | string |
| `contact_3_phone` | The phone number of the third contact person. | string |

2. **meeting-type.schema.json**
- **Description**: Lists available, proposed, and proposed changed meeting types as enumerations.

3. **feed.schema.json**
- **Description**: Defines the structure of a feed containing multiple meeting entries.

## Usage

These schemas can be used to validate JSON data structures in applications that require structured meeting information. They help ensure that data conforms to expected formats and constraints, reducing errors and improving data quality.

### PHP Example

Here is an example of how you might use a PHP library to validate data against the `meeting.schema.json`:

```php
<?php
require 'vendor/autoload.php';

use JsonSchema\Validator;
use JsonSchema\Constraints\Constraint;

$validator = new Validator();
$data = json_decode(file_get_contents('example.json'));
$schema = json_decode(file_get_contents('spec/meeting.schema.json'));

$validator->validate($data, $schema, Constraint::CHECK_MODE_APPLY_DEFAULTS);

if ($validator->isValid()) {
echo "The supplied JSON validates against the schema.\n";
} else {
echo "JSON does not validate. Violations:\n";
foreach ($validator->getErrors() as $error) {
echo sprintf("[%s] %s\n", $error['property'], $error['message']);
}
}
```

### Typescript Example

*(tested with `bun`)*

Here is an example of using json-schema-to-zod to generate typescript types and validation schemas (with zod) from the `meeting.schema.json`:

```typescript
import { jsonSchemaToZod } from "json-schema-to-zod";
import { resolveRefs } from "json-refs";
import { format } from "prettier";
import {writeFileSync} from 'fs'

const schemaUrl = 'https://raw.githubusercontent.com/code4recovery/spec/refs/heads/main/schema/meeting.schema.json'

const generateTypes = async () => {
// Get Json Schema from URL
const schemaObject = await (await fetch(schemaUrl)).json();

// Resolve all $refs in the schema object (ie. meeting-type.schema.json)
const { resolved } = await resolveRefs(schemaObject);

// Convert the schema to Zod types
const code = jsonSchemaToZod(resolved, { name: "MeetingSchema", module: "esm", type: true });

// Format the code
const formatted = await format(code, { parser: "typescript" });
return formatted
}

generateTypes().then((formatted: string) => {
console.log(formatted)
})
```

### JavaScript Example

Here is an example of how you might use the ajv library in JavaScript to validate data against the `meeting.schema.json`:

```javascript
const Ajv = require('ajv');
const ajv = new Ajv();
const meetingSchema = require('./spec/meeting.schema.json');
const data = {
"name": "Weekly Meditation Group",
"slug": "weekly-meditation-group",
"day": 1,
"time": "19:30",
"formatted_address": "123 Main St, Springfield, IL 62701, USA"
};

const validate = ajv.compile(meetingSchema);
const valid = validate(data);
if (!valid) console.log(validate.errors);
```

## Contribution

Contributions to improve and expand the schemas are welcome. Please ensure any changes are compatible with JSON Schema Draft-07 and include appropriate documentation.
33 changes: 33 additions & 0 deletions schema/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"$schema": "./meeting.schema.json",
"name": "Sunday Serenity",
"slug": "sunday-serenity-14",
"day": 0,
"time": "18:00",
"end_time": "19:30",
"location": "Alano Club",
"group": "The Serenity Group",
"notes": "Ring buzzer. Meeting is on the 2nd floor.",
"updated": "2014-05-31 14:32:23",
"url": "https://district123.org/meetings/sunday-serenity",
"types": [
"O",
"T",
"LGBTQ"
],
"address": "123 Main Street",
"city": "Anytown",
"state": "CA",
"postal_code": "98765",
"country": "US",
"approximate": "no",
"entity": "District 123",
"entity_email": "[email protected]",
"entity_location": "Example County, California",
"entity_logo": "https://district123.org/images/logo.svg",
"entity_phone": "+1-123-456-7890",
"entity_url": "https://district123.org",
"feedback_emails": [
"[email protected]"
]
}
10 changes: 10 additions & 0 deletions schema/feed.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://raw.githubusercontent.com/code4recovery/spec/refs/heads/main/schema/feed.schema.json",
"title": "Meeting Guide API Schema",
"description": "The feed of meetings",
"type": "array",
"items": {
"$ref": "https://raw.githubusercontent.com/code4recovery/spec/refs/heads/main/schema/meeting.schema.json"
}
}
112 changes: 112 additions & 0 deletions schema/meeting-type.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://raw.githubusercontent.com/code4recovery/spec/refs/heads/main/schema/meeting-type.schema.json",
"title": "Meeting Guide API Schema",
"description": "The meeting types available",
"type": "array",
"items": {
"anyOf": [
{
"$comment": "Currently Available Types",
"type": "string",
"enum": [
"11",
"12x12",
"A",
"ABSI",
"AL",
"AL-AN",
"AM",
"ASL",
"B",
"BA",
"BE",
"BI",
"BRK",
"C",
"CAN",
"CF",
"D",
"DA",
"DB",
"DD",
"DE",
"DR",
"EL",
"EN",
"FA",
"FF",
"FR",
"G",
"GR",
"H",
"HE",
"HI",
"HR",
"HU",
"ITA",
"JA",
"KOR",
"L",
"LGBTQ",
"LIT",
"LS",
"LT",
"M",
"MED",
"ML",
"N",
"NB",
"NDG",
"NO",
"O",
"OUT",
"P",
"POA",
"POC",
"POL",
"POR",
"PUN",
"RUS",
"S",
"SEN",
"SK",
"SM",
"SP",
"ST",
"SV",
"T",
"TC",
"TH",
"TL",
"TR",
"TUR",
"UK",
"W",
"X",
"XB",
"XT",
"Y"
]
},
{
"$comment": "Proposed Types",
"type": "string",
"enum": [
"BV-I",
"D-HOH",
"LO-I",
"QSL",
"RSL"
]
},
{
"$comment": "Proposed Changed Types",
"type": "string",
"enum": [
"LGBTQIAA+"
]
}
]
}
}
Loading