JSON API format in API-Platform - symfony

First of all I want to implement JSON API.
I follow tutorial on api platform and just like in example create entities and response is like
{
"links": {
"self": "/api/books"
},
"meta": {
"totalItems": 1,
"itemsPerPage": 30,
"currentPage": 1
},
"data": [
{
"id": "/api/books/1",
"type": "Book",
"attributes": {
"isbn": "9781782164104",
"title": "Persistence in PHP with the Doctrine ORM",
"description": "This book is designed for PHP developers and architects who want to modernize their skills through better understanding of Persistence and ORM.",
"author": "Kévin Dunglas",
"publicationDate": "2013-12-01T00:00:00+01:00",
"_id": 1
},
"relationships": {
"reviews": {
"data": [
{
"type": "Review",
"id": "/api/reviews/1"
}
]
}
}
}
]
}
My api_platform.yaml config
api_platform:
mapping:
paths: ['%kernel.project_dir%/src/Entity']
formats:
jsonapi:
mime_types: ['application/vnd.api+json']
So i have problem with id filed in data. I get id fields in format api/entityName/id but I just want to get number(string), just like in JSON API. So is there some configuration that i miss or is any way to achieve that

It was discussed here.
You need to use Normalizer or create custom getter.

All you need is to send
Accept: application/json
on request header.

Related

Is there a way to expand references in Swashbuckle to provide inline schemas?

Is there a mechanism in Swashbuckle that can prevent definitions from being created with referencing to them in parameters/responses/etc.?
By default, you might get a path that looks like this:
"/profile": {
"get": {
"summary": "Get my profile details.",
"produces": [
"application/json",
],
"parameters": [],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/ProfileModel"
}
}
}
}
}
But what I'd like is for it to expand the schema inline like this:
"/profile": {
"get": {
"summary": "Get my profile details.",
"produces": [
"application/json",
],
"parameters": [],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "id"
},
"firstName": {
"type": "string",
"description": "firstName"
},
"surname": {
"type": "string",
"description": "surname"
},
"emailAddress": {
"type": "string",
"description": "emailAddress"
}
}
}
}
}
}
}
I reviewed this StackOverflow question and I don't think it's what I'm looking for (or maybe misinterpreted).
Taken a look through the Swashbuckle README to understand its capabilities but coming up short. Any help here would be most appreciated.
For additional context, looking at the Swashbuckle PDF documentation in section 1.7, I essentially want to bypass or revert the action they describe as
automatically generating a corresponding schema for user-defined reference types and reference the definition via the $ref keyword.
Digging into the codebase a little, it looks like it's not possible at the moment.
However, you can create a custom ISchemaGenerator from the one in source and alter the GenerateConcreteSchema method under the DataType.Object case to not return as reference and this solves the issue.

Q: Linkedin Vector Assest API, Registering Multi-Part Upload - No metadata value in response

I'm attempting to complete a multipart upload using Linkedin V2 Vector Assets and i've noticed that when registering the upload, the metadata field comes back blank in the response.
Here's the request to register the upload https://api.linkedin.com/v2/assets?action=registerUpload
{
"registerUploadRequest":{
"owner":"urn:li:organization:71736744",
"recipes":["urn:li:digitalmediaRecipe:feedshare-video"],
"serviceRelationships":[
{"identifier":"urn:li:userGeneratedContent","relationshipType":"OWNER"}
],
"supportedUploadMechanism":["MULTIPART_UPLOAD"],
"fileSize":50866165
}
and here is the response (removed all but one partUploadRequests object to make the response easier to read)
{
"value": {
"uploadMechanism": {
"com.linkedin.digitalmedia.uploading.MultipartUpload": {
"partUploadRequests": [
{
"headers": {
"Content-Type": "application/octet-stream"
},
"byteRange": { "lastByte": 4194303, "firstByte": 0 },
"url": "https://www.linkedin.com/dms-uploads/C5605AQFnYcNsf7K5Yw/uploadedVideo?sau=aHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2FtYnJ5L2FtYnJ5LXZpZGVvLz94LWxpLWFtYnJ5LWVwPUFRRmp4SlBwRndkUUNnQUFBWGhjYkgwNzNuZmpacTRFM3AxUkpidTMxTlAxems3WmdoUHN1Ymp1TjVGTXVDRGFOaGczVnpHWXNpLW5OYWh2NlkxWkU5UDVIdktsQ2JxbGhhOUt1SElJSnBXTjI0TkEyWDIzM1ZiaS1aNW4yTmlXWWQyX1VlN1J2d0FEdkMwSG51ckNMY1ljMkdrczhKclFlZHRYNlZNN2dvTFJad2hpT0pxcFNZM29mXzdTTmRhZjZzQlNMS3FwaTJyWF9LYTRqTk9OcnBhTFpCam1KR3ZENEV3ZFd0VHEzNm44aEFQbDhCMmc3cVpOd3Q0Ny1TT1ZvcHRoT0dWcTB0cHAxU2VkbkY2aVNVQ3J6RVlwVHdzNDZTQlViME5HbGxITHo4a1ZNOGJxYkJjMDVCc054MDQ2ZDktZWdGb2RFa3ZKRmxsU0NRWFV2ZzdQb3VFaVNodkZtSHRYVHhLLWlkbnpKWjlQN1Q2b1ROQWJhWE5iR2g2QUdBQmQ3VVdjNkdGb01YaWFiazBhRlA4UzNpUXNlM05ISFNVdkFBdk1nSnV2a0xxWV9oYU1VTXdoeXFRT0w1a0NLM1NSd2RXTnpKSHZLMkhfY0ZqclYzcnB4VXJZckkxbUZ2QVl2Y3dUcVYyaDhWWHRpY1luNTA0am1jUjN3U0M5RVVQZEo2RFZEd1RJRmFvOTJYcmszbTFNS2pSRlFZMV94enVHZVk4SERKWTQwbDQySVRJNXlCLUp3b2V3Vjl3RGduOTZycmhoY1pLa0VOck5vdUZ4eDdodlBTNkZUVXcweXJWM3BaOUF5X2NtaHBXTVpwOVRFY0pJcGY3elFrQTF3ZFcyR3VIcEtGLUF4MldTZTdlR1pCOTdHaU5vLW9XamhkV2stR2MzNFh5UjFwckZsTF9sSFFUWU40S2pNLUI2Y2poZHFJV2xVTll6Z1lVaXdwNld2UEYwVFRObW5kQVgtTTBlX1VsaGFOQ190SDFEcG9Kem5IZExoN3IxMGk5VWE4MGpsZ3pDQzBsT3JKSkxuSEcwNm9jVzNJSzctT3NSZGhBSEFNdTBuWDNRdlhfSFoxWXpfNXgza3dyZzBPOVlmN2xIUFFiVW1lYllReUlJaGdxOEE1blpxVUxzeUpvZElLWk5WdUdlcjVuN21jTFV4TzRtNlBUczVtc3pHS0x4Z3o4b2FDdVNiWWliYzh2NkpxQktiN2RmejdnQWRFVVpfNnRLenVxUm11bGk5OGZVSVpOR3hfc3R1Mk9nVDYzYXRoQmZnRHQ0dGpnVi1BOWlaVXdtYWNLckxwVE5wNUdHZlBxZjhLaE1MZC1BVXotSVNoX19jRUlzM2laSXlpeC1pNlFpeGZyRmpxQnYwaDhwOGZpeXZ0Q2Job0xjU1g4aWNjX0lSX28xQXR0UmZB&pn=1&m=616825227&app=86804616&sync=0&v=beta&ut=1nBLJxAvwH5FI1",
"urlExpiresAt": 1616544717116
} ...
],
"metadata": ""
}
},
"asset": "urn:li:digitalmediaAsset:C5605AQFnYcNsf7K5Yw",
"mediaArtifact": "urn:li:digitalmediaMediaArtifact:(urn:li:digitalmediaAsset:C5605AQFnYcNsf7K5Yw,urn:li:digitalmediaMediaArtifactClass:uploadedVideo)"
}
}
The api documentation explains that I need to use the metadata value from the register upload response to complete the upload
I attempt making the request anyway without a value for the metadata field to https://api.linkedin.com/v2/assets?action=completeMultiPartUpload (removed all but one partUploadResponses object to make the response easier to read)
{
"completeMultipartUploadRequest": {
"mediaArtifact": "urn:li:digitalmediaMediaArtifact:(urn:li:digitalmediaAsset:C5605AQFnYcNsf7K5Yw,urn:li:digitalmediaMediaArtifactClass:uploadedVideo)",
"metadata": "",
"partUploadResponses": [
{
"headers": {
"ETag": "/ambry-video/signedId/AQGpSasdC3ezCgAAAXhcbTobXlB6_ujllr8BPUUAX4o9OgbHCxiRKoG9woM85dnGrxbUbd-5IXyMKO7syqyZXLgHFd8GQJkiMvvp1eHI9N32iJqMG-l_aFgSeXMbcqkFFcjuT22djM93dmKs_RBb58kppS3CadOPHSt5_tApCxAq0wgTfYQng3OkV_uVRdjIYftyfnHW3nF2vWz4hZBoX-YhmF6gDhXtN9dNTnU4QpHB7sGCecpjYgT8ypV-u5isvFrujHl3tl4.bin"
},
"httpStatusCode": 200
} ....
]
}
}
This comes back as a 200OK without any response body which is expected.
After that I check the upload status and which comes back with a code of SERVER_ERROR and I'm not able to create a post with the asset id of the uploaded asset.
Response from checking asset status https://api.linkedin.com/v2/assets/C5605AQFnYcNsf7K5Yw
{
"recipes": [
{
"recipe": "urn:li:digitalmediaRecipe:feedshare-video",
"status": "SERVER_ERROR"
}
],
"serviceRelationships": [
{
"relationshipType": "OWNER",
"identifier": "urn:li:userGeneratedContent"
}
],
"mediaTypeFamily": "VIDEO",
"created": 1616458317042,
"id": "C5605AQFnYcNsf7K5Yw",
"lastModified": 1616458454711,
"status": "ALLOWED"
}
Request to create a UGC post with the asset https://api.linkedin.com/v2/assets
{
"author": "urn:li:organization:71736744",
"lifecycleState": "PUBLISHED",
"specificContent": {
"com.linkedin.ugc.ShareContent": {
"media": [
{
"media": "urn:li:digitalmediaAsset:C5605AQFnYcNsf7K5Yw",
"status": "READY",
"title": {
"attributes": [],
"text": "Sample Video Create"
}
}
],
"shareCommentary": {
"attributes": [],
"text": "Some share text"
},
"shareMediaCategory": "VIDEO"
}
},
"visibility": {
"com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"
}
Response to the request
{
"serviceErrorCode": 0,
"message": "Resource assets does not exist",
"status": 404}
The only thing I can think of is since I don't have a metadata value when completing the upload I'm not able to use the video asset in UGC posts. Anyone encountered a problem similar to this?
Further Investigations
On further investigation the example from the API docs doesn't return a metadata field either. So this is what I think might be happening
I'm not uploading the file chunks correctly and the metadata field isn't required for completing the upload.
The API has a bug in it which prevents it from returning the metadata field when registering a multipart upload.
Figured it out, when using the slice method to break your file up into chunks it needs to be file.slice(firstByte, lastByte + 1)
It also seems that the metadata value from the register upload request isn't need to complete the upload.

JAGQL - Why do I need an id for a post call?

I'm using JAGQL to build a JSON API compatible express server. My database behind it is MongoDB (jsonapi-store-mongodb). I posted my question here as well: https://github.com/holidayextras/jsonapi-store-mongodb/issues/59
According to the JAGQL documentation, https://jagql.github.io/pages/project_setup/resources.html#generateid,
I am told that
generateId
By default, the server autogenerates a UUID for resources which are created without specifying an ID. To disable this behavior (for example, if the database generates an ID by auto-incrementing), set generateId to false. If the resource's ID is not a UUID, it is also necessary to specify an id attribute with the correct type. See /examples/resorces/autoincrement.js for an example of such a resource.
But when I send a POST request to one of my resources, I get this:
"jsonapi": {
"version": "1.0"
},
"meta": {},
"links": {
"self": "/myresource"
},
"errors": [
{
"status": "403",
"code": "EFORBIDDEN",
"title": "Param validation failed",
"detail": [
{
"message": "\"id\" is required",
"path": [
"id"
],
"type": "any.required",
"context": {
"key": "id",
"label": "id"
}
}
]
}
]
What am I missing?
See here for more details: https://github.com/jagql/framework/issues/106
In your resource definition, you want to add primaryKey: 'uuid':
{
resource: 'things',
handlers,
primaryKey: 'uuid',
attributes: {
...
}
}

Is there a way to support JSON schema references in Paw?

Paw has good tools for documenting simple APIs, but now I need to do something more complicated and I would like to use JSON Schema references.
For example, like the following snippet from the Swagger 2.0 examples, where the definitions are presented later in the document:
"post": {
"description": "Creates a new pet in the store. Duplicates are allowed",
"operationId": "addPet",
"parameters": [
{
"name": "pet",
"in": "body",
"description": "Pet to add to the store",
"required": true,
"schema": {
"$ref": "#/definitions/NewPet"
}
}
],
...
Is there a way to to this in Paw?

JSONAPI - Difference between self and related in a links resource

Why is the self and related references different in the below JSONAPI resource? Aren't they pointing to the same resource? What is the difference between going to /articles/1/relationships/tags and /articles/1/tags?
{
"links": {
"self": "/articles/1/relationships/tags",
"related": "/articles/1/tags"
},
"data": [
{ "type": "tags", "id": "2" },
{ "type": "tags", "id": "3" }
]
}
You can read about that here: https://github.com/json-api/json-api/issues/508.
Basically, with /articles/1/relationships/tags response will be object which represents relationship between articles and tags. The response could be something like this (what you put in your question):
{
"links": {
"self": "/articles/1/relationships/tags",
"related": "/articles/1/tags"
},
"data": [
{ "type": "tags", "id": "2" },
{ "type": "tags", "id": "3" }
]
}
This response gives only the necessary data (in primary data attribute - data) to manipulate the relationship and not resources connected with relationship. That being said, you'll call /articles/1/relationships/tags if you want to create new relationship, add a new tag (basically updating relationship) to article, read which tags belong to article (you only need identity to search them on server) or delete article tags.
On the other hand, calling /articles/1/tags will respond with tags as primary data with all the other properties that they have (articles, relationships, links, and other top-level attributes such include, emphasized text, links and/or jsonapi).
They are different. Here is an example from my project.
Try Get http://localhost:3000/phone-numbers/1/relationships/contact you will get response like this:
{
"links": {
"self": "http://localhost:3000/phone-numbers/1/relationships/contact",
"related": "http://localhost:3000/phone-numbers/1/contact"
},
"data": {
"type": "contacts",
"id": "1"
}
}
You didn't get the attributes and relationships which is probably you want to retrieve.
Then
Try Get http://localhost:3000/phone-numbers/1/contact you will get response like this:
{
"data": {
"id": "1",
"type": "contacts",
"links": {
"self": "http://localhost:3000/contacts/1"
},
"attributes": {
"name-first": "John",
"name-last": "Doe",
"email": "john.doe#boring.test",
"twitter": null
},
"relationships": {
"phone-numbers": {
"links": {
"self": "http://localhost:3000/contacts/1/relationships/phone-numbers",
"related": "http://localhost:3000/contacts/1/phone-numbers"
}
}
}
}
}
You can see you retrieved all the information you want, including the attributes and relationships.
But you should know that relationships can be used for some purpose. Please read http://jsonapi.org/format/#crud-updating-to-one-relationships as a sample.

Resources