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 ability for developers to support additional MIME types in FileMiddleware #657

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

mredig
Copy link
Contributor

@mredig mredig commented Jan 15, 2025

Added additionalMediaTypeExtensions to FileMiddleware with a withAdditionalMediaType method, adding additional media types, to retain object immutability.

I also went out on a limb and funneled the FileMiddleware inits through a single initializer as that better supports this pattern.

This would resolve #656

A test case was added to confirm expected behavior.

@Joannis
Copy link
Member

Joannis commented Jan 16, 2025

I actually think it's a good case for making that property explicitly mutable. I don't see any reason we wouldn't do so. While adding a function to modify those properties is nice, it's certainly also no harm and potentially helpful to know all registered file extensions.

@Joannis
Copy link
Member

Joannis commented Jan 16, 2025

What do you think @adam-fowler ?

@mredig
Copy link
Contributor Author

mredig commented Jan 16, 2025

I actually think it's a good case for making that property explicitly mutable. I don't see any reason we wouldn't do so. While adding a function to modify those properties is nice, it's certainly also no harm and potentially helpful to know all registered file extensions.

The main reason I took this approach was because it isn't immediately obvious that the String key in the dictionary is the file extension, while the method nicely resolves this issue.

I guess I don't have a strong feeling either way to make it mutable or not, but as it is, future maintainers would have the explicit context of associating the file extension with the mime type instead of having to intuit the association.

@mredig
Copy link
Contributor Author

mredig commented Jan 16, 2025

... potentially helpful to know all registered file extensions.

I could also make it public, but keep it immutable. :)

@Joannis
Copy link
Member

Joannis commented Jan 16, 2025

That makes sense!

@mredig
Copy link
Contributor Author

mredig commented Jan 16, 2025

That makes sense!

So, leave it as it is, but make the property public?

@adam-fowler
Copy link
Member

I actually think it's a good case for making that property explicitly mutable. I don't see any reason we wouldn't do so. While adding a function to modify those properties is nice, it's certainly also no harm and potentially helpful to know all registered file extensions.

I don't think it's a great idea to make what should be a static list (you aren't going to change this while the server is running) mutable.

urlBasePath: urlBasePath,
cacheControl: cacheControl,
searchForIndexHtml: searchForIndexHtml,
additionalMediaTypeExtensions: [:]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mediaTypeFileExtensionMap?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of should it be the other way fileExtensionMediaTypeMap? What do you think

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they are about equal in terms of clarity, but the first is more concise.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they are about equal in terms of clarity, but the first is more concise.

I just realized they are the same character count, but the second looks longer lol

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just pushed - I also changed
public func withAdditionalMediaType(_ mediaType: MediaType, forFileExtension fileExtension: String) -> FileMiddleware
to
public func withAdditionalMediaType(_ mediaType: MediaType, mappedToFileExtension fileExtension: String) -> FileMiddleware
to match.

Copy link
Member

@adam-fowler adam-fowler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of comments but otherwise looks good

@@ -52,6 +52,7 @@ where Provider.FileAttributes: FileMiddlewareFileAttributes {
let searchForIndexHtml: Bool
let urlBasePath: String?
let fileProvider: Provider
public let mediaTypeFileExtensionMap: [String: MediaType]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason this needs to be public.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re @Joannis

it's certainly also no harm and potentially helpful to know all registered file extensions.

I thought it was a good point. I could see a need to introspect what the customizations are.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until someone needs it I'd prefer we leave it private. Setting it to public means setting it in stone until the next major version.

self.mediaTypeFileExtensionMap = mediaTypeFileExtensionMap
}

public func withAdditionalMediaType(_ mediaType: MediaType, mappedToFileExtension fileExtension: String) -> FileMiddleware {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worthwhile adding a function to add multiple media types.

public func withAdditionalMediaTypes(_ types: [String: MediaType]) -> FileMiddleware

Copy link
Contributor Author

@mredig mredig Jan 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are sample call sites to help visualize the difference:

FileMiddleware(".")
    .withAdditionalMediaType(hlsStream, mappedToFileExtension: "m3u8")
    .withAdditionalMediaType(MediaType(type: .application, subType: "foo"), mappedToFileExtension: "foo")
    .withAdditionalMediaType(MediaType(type: .application, subType: "bar"), mappedToFileExtension: "bar")
    .withAdditionalMediaType(MediaType(type: .application, subType: "baz"), mappedToFileExtension: "baz")
FileMiddleware(".")
    .withAdditionalMediaTypes([
        "m3u8": hlsStream,
        "foo": MediaType(type: .application, subType: "foo"),
        "bar": MediaType(type: .application, subType: "bar"),
        "baz": MediaType(type: .application, subType: "baz"),
    ])

I definitely like the less imposing block of text, but it still retains the original issue I was trying to avoid in that it's not super apparent that the keys in the dictionary are file extensions.

...future maintainers would have the explicit context of associating the file extension with the mime type instead of having to intuit the association.

What would you think of

public func withAdditionalMediaTypes(forFileExtensions extensionToMediaTypeMap: [String: MediaType]) -> FileMiddleware

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll get on it!

@mredig
Copy link
Contributor Author

mredig commented Jan 18, 2025

I looked at the details for the validation failure and it isn't making sense to me. Does it want me to format like this?!?!

let extensions = 
    extensionToMediaTypeMap
    .reduce(into: mediaTypeFileExtensionMap) {
        $0[$1.key.lowercased()] = $1.value
    }

withAdditionalMediaTypes(forFileExtensions: [fileExtension: mediaType])
}

public func withAdditionalMediaTypes(forFileExtensions extensionToMediaTypeMap: [String: MediaType]) -> FileMiddleware {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adam-fowler Is it worth adding a custom ExpressibleByDictionaryLiteral type for this dictionary use case? That way we can represent it in, what I believe, would be a clearer API surface. That could also cascade into the public var extensionMap: ... { get } down the line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we did, that would also allow us to account for non lowercase file extensions through the custom type, superseding the need for #661

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

MediaType isn't extensible
3 participants