---
# System prepended metadata

title: Envelopes

---

## Questions:
* How should registration of SCRUD resource work in Django
    * For example, where should the registration happen, and what should that imply?

### Ideal Answer
Start with a `resource_types` table and autoload that from `conf.py` based on static resources in the application. This would require metaclasses that know how to read that table and generate the models, serializers, and Django REST Framework views dynamically based on the configured SCRUD resources.

#### Stepping Stones Toward Ideal for django
1. Define a model for `Resource`
    a. It has the fields `schema` and `context` that are both `Resource` links. Nullable.
    b. It has a field `content` that is the JSON for the content
2. Define a serializer for `Resource`.
3. Define a DRF view for `Resource`.
4. Define a way to "register" `Resource` instances based on static files in the app.

```python
#Django, phase 1
class Resource(Model):
    # The actual JSON content for this resource
    content = JsonField()
    # JSON-Schema for this resource
    schema = ForeignKey(Resource, nullable=True)
    # JSON-LD for this resource
    context = ForeignKey(Resource, nullable=True)
    modified_at = DateTime()
    etag = StringField()
```

```python
#Django, phase 2, we could start here...
# this will support something like GET /resource_type/schema?uri=http://schema.org/person
# to get the json-schema for Person
# or GET /resource_type/context?uri=http://schema.org/person
# to get the json-ld for Person
class ResourceType(Model):
    type_uri: StringField()
    
    # Necessary IFF there is a collection endpoint
    # associated with this ResourceType
    slug: StringField(nullable=true)
    
    # require either schema or schema_uri
    schema = ForeignKey(Resource, nullable=True)
    schema_uri = StringField(nullable=True)
    
    # require either context or context_uri
    context = ForeignKey(Resource, nullable=True)
    context_uri = StringField(nullable=True)
    
class Resource(Model):
    # The actual JSON content for this resource
    content = JsonField()
    resource_type = ForeignKey(ResourceType)
    modified_at = DateTime()
    etag = StringField()
```


#### FASTAPI approach, start with ABC typing
1. Generate the schema and context from the types!

```python
class Resource(Model):
    content: Content
    schema: Schema
    context: Context
    modified_at: DateTime
    etag: String
```


```python
from scrud_django import register_resource_type

...
# This results in the creation of the model, serializer, view, etc
# for the resource specified by the json schema and json-ld context
register_resource_type(
    'my_resources',
    resource_type_uri,
    json_schema,
    json_ld_context)
    
register_resource_type(
    collection_slug='mystuff',
    schema=json_schema,
    context=json_ld_context,
    mixins=[my_query_mixin, my_search_mixin]
)
```

```json
[{
  "url": {}
  , "last_modified": ""
  , "etag": ""
  , "content": {
        "prop1": "foo"
        , "prop2": "bar"
        , "really_big_property":
          "url": "/path/to/big/image.png"
    }
}
, {}
]
```

```javascript
contextRdf.lookup("foo.bar[2].baz")
-> "http://api.openteams.com/json-ld/baz"

contextRdf.supertypes("http://api.openteams.com/json-ld/baz")
-> ["http://schema.org/Person"]
```

```json
{
    "next": ""
    , "prev": ""
    , "results": [{
        "url": ""
        , "last_modified": ""
        , "etag": ""
        , "content": { # what is the json-ld and json schema of this?
            ...
        }
    }]
}
```

```json
{
    "context": "jsonld"
    , "@id": "https://api.openteams.com/json-ld/PeopleQueryResult"
    , "next": {}
    , "prev": {}
    "results": {
        "@id": "https://api.openteams.com/json-ld/PeopleQueryMatch"
        "isa": "https://api.openteams.com/json-ld/EnvelopeArray"
        "contains": "https://api.openteams.com/json-ld/Person"
        "schema": "https://api.openteams.com/schema/Person"
    }
}
```

# Envelopes

We're going to need a json-ld approach to indicating that a property is an envelope. What's more, we'll need to indicate the type of the resource contained within the envelope!

## *Key Thing to Remember*

The envelopes have caching headers! So, when processing a resource, if the json-ld context specifies `Envelope` or `EnvelopeArray` properties - cache their contents as resources by grabbing the caching headers in the containing envelope.

# Resource with an envelope

Let's imagine a resource that contains a "status" resource in an envelope.

In this example, this composite resource contains a `status` that is another resource.

```json
{
    ...
    "status": {
        "url": "/thing/42/status"
        , "last_modified": ""
        , "etag": ""
        , "content": {
            "state": "in-progress"
        }
    }
    ...
}
```

So, what would the json-ld look like?

```json
{
    "openteams": "https://api.openteams.com/json-ld/"
    ...
    "status": {
        "@type": "https://api.openteams.com/json-ld/Envelope"
        , "content": {
            "@type": "https://api/openteams.com/json-ld/Status"
        }
    }
}
```

So... if I have this right, the `status.content` property is a `https://api.openteams.com/json-ld/Status` resource.

## What about collections?

Let's say I had a collection of Partner Profile resources

```json
{
    ...
    "profiles": [
        {
            "url": ""
            , "last_modified": ""
            , "etag": ""
            , "content": {
                ...
            }
        }
    ]
}
```

How do we indicate that the elements of the `profiles` array are of resource type `https://api.openteams.com/json-ld/PartnerProfile`?

```json
{
    ...
    "profiles": {
        "@type": "https://api.openteams.com/json-ld/EnvelopeArray"
        , "content": "https://api.openteams.com/json-ld/PartnerProfile"
    }
}
```

# Service Catalog

For the Django app, we're going to need a way to advertise endpoints available from the app to bootstrap the client.

GET this from `https://backend.openteams.com/services`:

```json
{
    "https://api.openteams.com/json-ld/PartnerProfile-Listing": "https://backend.openteams.com/partner-profiles"
    , ...
}
```

The above indicates that there is a "Partner Profile Listing" resource (`https://api.openteams.com/json-ld/PartnerProfile-Listing`) located at `https://backend.openteams.com/partner-profiles`.

## What about just an array?

```json
["https://backend.openteams.com/partner-profiles"
 , "https://backend.openteams.com/client-profiles"
 , "https://backend.openteams.com/user"
 , "https://backend.openteams.com/initiatives"
 , "https://backend.openteams.com/projects"
]
```

The problem is in bootstrapping the client - you would have to perform OPTIONS on every element in the list to get the mapping needed. Let's assume a "configured" client - that is, it's set up to start from somewhere, like, listing several of the items. It's poor form to perform a bunch of calls to build the RDF Resource Type -> URL map just to get the client started.
