nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: jeregrine/jsonapi
Pull request #85 (2017-11-15 17:07:55)

Avoid calling Enum.map on maps that happen to be structs
In cases where a struct is passed to `underscore`, it currently tries to call `Enum.map` on it, which causes something like this:

```
** (Protocol.UndefinedError) protocol Enumerable not implemented for ~N[2017-11-15 16:56:31.268901]
```


Patch:
diff --git a/lib/jsonapi/utils/underscore.ex b/lib/jsonapi/utils/underscore.ex
index 133eaa7..a3fd2b6 100644
--- a/lib/jsonapi/utils/underscore.ex
+++ b/lib/jsonapi/utils/underscore.ex
@@ -15,6 +15,10 @@ defmodule JSONAPI.Utils.Underscore do
     String.replace(value, "_", "-")
   end
 
+  def underscore(%{__struct__: _} = value) when is_map(value) do
+    value
+  end
+
   def underscore(value) when is_map(value) do
     value
     |> Enum.map(&underscore/1)


Test patch:
diff --git a/test/serializer_test.exs b/test/serializer_test.exs
index b1da947..1fa9e0c 100644
--- a/test/serializer_test.exs
+++ b/test/serializer_test.exs
@@ -5,7 +5,7 @@ defmodule JSONAPISerializerTest do
   defmodule PostView do
     use JSONAPI.View
 
-    def fields, do: [:text, :body, :full_description]
+    def fields, do: [:text, :body, :full_description, :inserted_at]
     def meta(data, _conn), do: %{meta_text: "meta_#{data[:text]}"}
     def type, do: "mytype"
     def relationships do
@@ -207,6 +207,7 @@ defmodule JSONAPISerializerTest do
     data = %{
       id: 1,
       text: "Hello",
+      inserted_at: NaiveDateTime.utc_now,
       body: "Hello world",
       full_description: "This_is_my_description",
       author: %{ id: 2, username: "jbonds", first_name: "jerry", last_name: "bonds"},
@@ -224,6 +225,7 @@ defmodule JSONAPISerializerTest do
     included = encoded[:included]
 
     assert attributes["full-description"] == data[:full_description]
+    assert attributes["inserted-at"] == data[:inserted_at]
     assert Enum.find(included, fn(i) -> i[:type] == "user" && i[:id] == "2" end)[:attributes]["last-name"] == "bonds"
     assert Enum.find(included, fn(i) -> i[:type] == "user" && i[:id] == "4" end)[:attributes]["last-name"] == "bronds"
     assert List.first(relationships["best-comments"][:data])[:id] == "5"
Repository: jeregrine/jsonapi
Pull request #86 (2017-11-17 17:19:56)

merge master from origin

StareIntoTheBeard: @jeregrine rebuilt the branch and reopened the PR as a result.

Patch:
diff --git a/lib/jsonapi/deprecation.ex b/lib/jsonapi/deprecation.ex
index d743732..1628bb0 100644
--- a/lib/jsonapi/deprecation.ex
+++ b/lib/jsonapi/deprecation.ex
@@ -1,5 +1,11 @@
 defmodule Deprecation do
-  @moduledoc false
+  @moduledoc """
+    Generate warnings in places where we want to deprecate functions or struct parameters
+  """
+
+  @doc """
+    Generates a deprecation warning for `includes` in the JSONAPI.Config struct.
+  """
 
   def warn(:includes) do
     IO.warn "`%JSONAPI.Config{}.includes` is deprecated; call `%JSONAPI.Config{}.include` instead.",
diff --git a/lib/jsonapi/serializer.ex b/lib/jsonapi/serializer.ex
index e5eea61..9798f3c 100644
--- a/lib/jsonapi/serializer.ex
+++ b/lib/jsonapi/serializer.ex
@@ -22,7 +22,9 @@ defmodule JSONAPI.Serializer do
     {to_include, encoded_data} = encode_data(view, data, conn, query_includes)
 
     %{
-      links: %{},
+      links: %{
+        self: view.url_for(data, conn)
+      },
       data: encoded_data,
       included: flatten_included(to_include)
     }


Test patch:
diff --git a/test/serializer_test.exs b/test/serializer_test.exs
index 1fa9e0c..65a133c 100644
--- a/test/serializer_test.exs
+++ b/test/serializer_test.exs
@@ -162,7 +162,7 @@ defmodule JSONAPISerializerTest do
     assert Enum.count(encoded[:included]) == 1
   end
 
-  test "serialize handles a relationship self link" do
+  test "serialize handles a relationship self link on a show request" do
     data = %{
       id: 1,
       text: "Hello",
@@ -177,6 +177,12 @@ defmodule JSONAPISerializerTest do
     assert encoded_data[:relationships][:author][:links][:self] == "/mytype/1/relationships/author"
   end
 
+  test "serialize handles a relationship self link on an index request" do
+    encoded = Serializer.serialize(PostView, [], nil)
+
+    assert encoded[:links][:self] == "/mytype"
+  end
+
   test "serialize handles including from the query" do
     data = %{
       id: 1,
Repository: jeregrine/jsonapi
Pull request #88 (2017-12-13 18:03:32)

Remove top level links if configured
Looks like links can be both top level and resource.  This removes the top level as well if configured.

doomspork: Thank you @snewcomer 😁  

@jeregrine any thoughts?
snewcomer: Just pinging this again.  Thanks for the reviews!
doomspork: Thank you @snewcomer 👍   Until @jeregrine can cut a new release you'll need to use master:

```elixir
{:jsonapi, github: "jeregrine/jsonapi"}
```

Patch:
diff --git a/lib/jsonapi/serializer.ex b/lib/jsonapi/serializer.ex
index 9798f3c..1f6fa07 100644
--- a/lib/jsonapi/serializer.ex
+++ b/lib/jsonapi/serializer.ex
@@ -21,13 +21,11 @@ defmodule JSONAPI.Serializer do
 
     {to_include, encoded_data} = encode_data(view, data, conn, query_includes)
 
-    %{
-      links: %{
-        self: view.url_for(data, conn)
-      },
+    encoded_data = %{
       data: encoded_data,
       included: flatten_included(to_include)
     }
+    merge_links(encoded_data, data, view, conn, remove_links?())
   end
 
   def encode_data(view, data, conn, query_includes) when is_list(data) do
@@ -47,7 +45,7 @@ defmodule JSONAPI.Serializer do
       relationships: %{}
     }
 
-    doc = merge_links(encoded_data, data, view, conn, Application.get_env(:jsonapi, :remove_links, false))
+    doc = merge_links(encoded_data, data, view, conn, remove_links?())
 
     doc =
       case view.meta(data, conn) do
@@ -109,10 +107,10 @@ defmodule JSONAPI.Serializer do
   end
 
   def encode_relation({rel_view, rel_data, _rel_url, _conn} = info) do
-    %{
+    data = %{
       data: encode_rel_data(rel_view, rel_data)
     }
-    |> merge_related_links(info, Application.get_env(:jsonapi, :remove_links, false))
+    merge_related_links(data, info, remove_links?())
   end
 
   defp merge_links(doc, data, view, conn, false) do
@@ -179,4 +177,6 @@ defmodule JSONAPI.Serializer do
       data
     end
   end
+
+  defp remove_links?, do: Application.get_env(:jsonapi, :remove_links, false)
 end
\ No newline at end of file


Test patch:
diff --git a/test/serializer_test.exs b/test/serializer_test.exs
index 65a133c..898d4eb 100644
--- a/test/serializer_test.exs
+++ b/test/serializer_test.exs
@@ -66,9 +66,11 @@ defmodule JSONAPISerializerTest do
     }
 
     encoded = Serializer.serialize(PostView, data, nil)
+    assert encoded[:links][:self] == PostView.url_for(data, nil)
     encoded_data = encoded[:data]
     assert encoded_data[:id] == PostView.id(data)
     assert encoded_data[:type] == PostView.type()
+    assert encoded_data[:links][:self] == PostView.url_for(data, nil)
 
     assert %{meta_text: "meta_Hello"} = encoded_data[:meta]
 
@@ -273,6 +275,7 @@ defmodule JSONAPISerializerTest do
 
     refute relationships[:links]
     refute encoded[:data][:links]
+    refute encoded[:links]
 
     Application.delete_env(:jsonapi, :remove_links)
   end
Repository: jeregrine/jsonapi
Pull request #103 (2018-04-15 10:53:37)

Do not build relationships section for not loaded relationships
Currently if a resource has defined relationships on its view it is always generated an record in the `relationships` section. If the relationship is not loaded, it generates a relationship record with `"id": null` and record type. 

This is not precisely per spec and can cause weird issues with front-end libraries when a record appears in relationships section with an id value of null.

Also, in case of one-to-many relationships, having a single record with id null can be misleading.

This PR updates the logic to not include an empty record if the relationship is not loaded.

jeregrine: Thanks! 💟 

Patch:
diff --git a/lib/jsonapi/serializer.ex b/lib/jsonapi/serializer.ex
index e0fd14e..47b7821 100644
--- a/lib/jsonapi/serializer.ex
+++ b/lib/jsonapi/serializer.ex
@@ -59,9 +59,10 @@ defmodule JSONAPI.Serializer do
     encode_relationships(conn, doc, {view, data, query_includes, valid_includes})
   end
 
-  def encode_relationships(conn, doc, {view, _, _, _} = view_info) do
-    rels = view.relationships()
-    Enum.map_reduce(rels, doc, &build_relationships(conn, view_info, &1, &2))
+  def encode_relationships(conn, doc, {view, data, _, _} = view_info) do
+    view.relationships()
+    |> Enum.filter(&is_data_loaded?(Map.get(data, elem(&1, 0))))
+    |> Enum.map_reduce(doc, &build_relationships(conn, view_info, &1, &2))
   end
 
   def build_relationships(


Test patch:
diff --git a/test/serializer_test.exs b/test/serializer_test.exs
index 727f374..e85e2e6 100644
--- a/test/serializer_test.exs
+++ b/test/serializer_test.exs
@@ -181,7 +181,7 @@ defmodule JSONAPISerializerTest do
     assert attributes[:body] == data[:body]
 
     assert encoded_data[:links][:self] == PostView.url_for(data, nil)
-    assert map_size(encoded_data[:relationships]) == 2
+    assert map_size(encoded_data[:relationships]) == 1
 
     assert Enum.count(encoded[:included]) == 1
   end
@@ -206,7 +206,7 @@ defmodule JSONAPISerializerTest do
     assert attributes[:body] == data[:body]
 
     assert encoded_data[:links][:self] == PostView.url_for(data, nil)
-    assert map_size(encoded_data[:relationships]) == 2
+    assert map_size(encoded_data[:relationships]) == 1
 
     assert Enum.count(encoded[:included]) == 1
   end
Repository: jeregrine/jsonapi
Pull request #144 (2018-12-12 17:14:03)

Set `Content-Type` for Errors
Prior to this change errors lacked this content type. This may confuse
some consumers of the API.


Patch:
diff --git a/lib/jsonapi/error_view.ex b/lib/jsonapi/error_view.ex
index 2befefb..eb54337 100644
--- a/lib/jsonapi/error_view.ex
+++ b/lib/jsonapi/error_view.ex
@@ -2,7 +2,7 @@ defmodule JSONAPI.ErrorView do
   @moduledoc """
   """
 
-  import Plug.Conn, only: [send_resp: 3, halt: 1]
+  import Plug.Conn, only: [send_resp: 3, halt: 1, put_resp_content_type: 2]
 
   @crud_message "Check out http://jsonapi.org/format/#crud for more info."
 
@@ -69,6 +69,7 @@ defmodule JSONAPI.ErrorView do
 
   def send_error(conn, status, error) do
     conn
+    |> put_resp_content_type("application/vnd.api+json")
     |> send_resp(status, error)
     |> halt
   end


Test patch:
diff --git a/test/jsonapi/plugs/content_type_negotiation_test.exs b/test/jsonapi/plugs/content_type_negotiation_test.exs
index 7dc13b0..bb34251 100644
--- a/test/jsonapi/plugs/content_type_negotiation_test.exs
+++ b/test/jsonapi/plugs/content_type_negotiation_test.exs
@@ -171,4 +171,21 @@ defmodule JSONAPI.ContentTypeNegotiationTest do
     assert conn.halted
     assert 406 == conn.status
   end
+
+  test "returned error has correct content type" do
+    conn =
+      :post
+      |> conn("/example", "")
+      |> Plug.Conn.put_req_header(
+        "accept",
+        "application/vnd.api+json; version=1.0, application/vnd.api+json; version=1.0"
+      )
+      |> ContentTypeNegotiation.call([])
+
+    assert conn.halted
+
+    assert Plug.Conn.get_resp_header(conn, "content-type") == [
+             "application/vnd.api+json; charset=utf-8"
+           ]
+  end
 end
Repository: jeregrine/jsonapi
Pull request #206 (2019-06-04 20:41:23)

Use string status codes in error responses
The [JSON:API spec for errors](https://jsonapi.org/format/#errors) says that the status should be "expressed as a string value" so this PR makes that change!



Patch:
diff --git a/lib/jsonapi/error_view.ex b/lib/jsonapi/error_view.ex
index c172505..96778d8 100644
--- a/lib/jsonapi/error_view.ex
+++ b/lib/jsonapi/error_view.ex
@@ -10,7 +10,7 @@ defmodule JSONAPI.ErrorView do
   def build_error(title, status, detail, pointer \\ nil, meta \\ nil) do
     error = %{
       detail: detail,
-      status: status,
+      status: Integer.to_string(status),
       title: title
     }
 
@@ -99,6 +99,10 @@ defmodule JSONAPI.ErrorView do
     send_error(conn, status, json)
   end
 
+  def send_error(conn, status, error) when is_binary(status) do
+    send_error(conn, String.to_integer(status), error)
+  end
+
   def send_error(conn, status, error) do
     conn
     |> put_resp_content_type(JSONAPI.mime_type())


Test patch:
diff --git a/test/jsonapi/plugs/format_required_test.exs b/test/jsonapi/plugs/format_required_test.exs
index 2d0acd2..3bb5ca1 100644
--- a/test/jsonapi/plugs/format_required_test.exs
+++ b/test/jsonapi/plugs/format_required_test.exs
@@ -138,7 +138,7 @@ defmodule JSONAPI.FormatRequiredTest do
              "detail" =>
                "Check out https://jsonapi.org/format/#crud-updating-to-many-relationships for more info.",
              "source" => %{"pointer" => "/data"},
-             "status" => 400,
+             "status" => "400",
              "title" =>
                "Data parameter has multiple Resource Identifier Objects for a non-relationship endpoint"
            } = error
Repository: jeregrine/jsonapi
Pull request #221 (2020-02-11 23:29:14)

Return correct error for patch calls missing data[type]
With a PATCH call that is missing the `type`, we were receiving an error that the `id` was missing even when it was present. This PR updates the `FormatRequired` plug to return the correct error and adds a test for it. Examples given below.

When sending this payload
```elixir
{
  "data" => {
    "id" => 12345,
    "attributes" => {
      "stuff" => "things"
    }
  }
}
```
this error was being returned
```elixir
{
  "errors" => [
    {
      "detail" => "Check out http://jsonapi.org/format/#crud for more info.",
      "source" => {
        "pointer" => "/data/id"
      },
      "status" => "400",
      "title" => "Missing id in data parameter"
    }
  ]
}
```
we would expect to receive an error like this
```elixir
{
  "errors" => [
    {
      "detail" => "Check out http://jsonapi.org/format/#crud for more info.",
      "source" => {
        "pointer" => "/data/type"
      },
      "status" => "400",
      "title" => "Missing type in data parameter"
    }
  ]
}
```


Patch:
diff --git a/lib/jsonapi/plugs/format_required.ex b/lib/jsonapi/plugs/format_required.ex
index 521aa87..a33e9b8 100644
--- a/lib/jsonapi/plugs/format_required.ex
+++ b/lib/jsonapi/plugs/format_required.ex
@@ -25,10 +25,14 @@ defmodule JSONAPI.FormatRequired do
 
   def call(%{params: %{"data" => %{"type" => _, "id" => _}}} = conn, _), do: conn
 
-  def call(%{method: "PATCH", params: %{"data" => %{"attributes" => _}}} = conn, _) do
+  def call(%{method: "PATCH", params: %{"data" => %{"attributes" => _, "type" => _}}} = conn, _) do
     send_error(conn, missing_data_id_param())
   end
 
+  def call(%{method: "PATCH", params: %{"data" => %{"attributes" => _, "id" => _}}} = conn, _) do
+    send_error(conn, missing_data_type_param())
+  end
+
   def call(%{params: %{"data" => %{"attributes" => _}}} = conn, _),
     do: send_error(conn, missing_data_type_param())
 


Test patch:
diff --git a/test/jsonapi/plugs/format_required_test.exs b/test/jsonapi/plugs/format_required_test.exs
index 3bb5ca1..ba5e29d 100644
--- a/test/jsonapi/plugs/format_required_test.exs
+++ b/test/jsonapi/plugs/format_required_test.exs
@@ -78,6 +78,23 @@ defmodule JSONAPI.FormatRequiredTest do
            } = error
   end
 
+  test "halts and returns an error for missing type in data param on a patch" do
+    conn =
+      :patch
+      |> conn("/example", Jason.encode!(%{data: %{attributes: %{}, id: "something"}}))
+      |> call_plug
+
+    assert conn.halted
+    assert 400 == conn.status
+
+    %{"errors" => [error]} = Jason.decode!(conn.resp_body)
+
+    assert %{
+             "source" => %{"pointer" => "/data/type"},
+             "title" => "Missing type in data parameter"
+           } = error
+  end
+
   test "does not halt if type and id members are present on a patch" do
     conn =
       :patch