New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@platformatic/sql-openapi

Package Overview
Dependencies
Maintainers
5
Versions
331
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@platformatic/sql-openapi - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

.nyc_output/42d15934-e8f2-45a1-954f-31efa1455bf6.json

2

.nyc_output/processinfo/index.json

@@ -1,1 +0,1 @@

{"processes":{"37c0cdcb-b739-46c8-8447-b68739045984":{"parent":"d2b4c28f-108b-4e08-b1f9-d15c96266f9d","externalId":"test/ignore.test.js","children":[]},"403bc0e6-1fbc-4c86-8bb1-d884cc4b3fae":{"parent":"d2b4c28f-108b-4e08-b1f9-d15c96266f9d","externalId":"test/hooks.test.js","children":[]},"6c3390ed-7e3e-4b9a-8d8d-b449f3310cd2":{"parent":"d2b4c28f-108b-4e08-b1f9-d15c96266f9d","externalId":"test/where.test.js","children":[]},"9855f880-a4e8-4d3f-804c-21a19b5ac89f":{"parent":"d2b4c28f-108b-4e08-b1f9-d15c96266f9d","externalId":"test/simple.test.js","children":[]},"d2b4c28f-108b-4e08-b1f9-d15c96266f9d":{"parent":null,"children":["37c0cdcb-b739-46c8-8447-b68739045984","403bc0e6-1fbc-4c86-8bb1-d884cc4b3fae","6c3390ed-7e3e-4b9a-8d8d-b449f3310cd2","9855f880-a4e8-4d3f-804c-21a19b5ac89f","e3781dc6-7ce2-435f-862d-d1ab33e8f35c"]},"e3781dc6-7ce2-435f-862d-d1ab33e8f35c":{"parent":"d2b4c28f-108b-4e08-b1f9-d15c96266f9d","externalId":"test/order_by.test.js","children":[]}},"files":{"/Users/matteo/Repositories/platformatic/packages/sql-openapi/index.js":["37c0cdcb-b739-46c8-8447-b68739045984","403bc0e6-1fbc-4c86-8bb1-d884cc4b3fae","6c3390ed-7e3e-4b9a-8d8d-b449f3310cd2","9855f880-a4e8-4d3f-804c-21a19b5ac89f","e3781dc6-7ce2-435f-862d-d1ab33e8f35c"],"/Users/matteo/Repositories/platformatic/packages/sql-openapi/lib/entity-to-routes.js":["37c0cdcb-b739-46c8-8447-b68739045984","403bc0e6-1fbc-4c86-8bb1-d884cc4b3fae","6c3390ed-7e3e-4b9a-8d8d-b449f3310cd2","9855f880-a4e8-4d3f-804c-21a19b5ac89f","e3781dc6-7ce2-435f-862d-d1ab33e8f35c"]},"externalIds":{"test/ignore.test.js":{"root":"37c0cdcb-b739-46c8-8447-b68739045984","children":[]},"test/hooks.test.js":{"root":"403bc0e6-1fbc-4c86-8bb1-d884cc4b3fae","children":[]},"test/where.test.js":{"root":"6c3390ed-7e3e-4b9a-8d8d-b449f3310cd2","children":[]},"test/simple.test.js":{"root":"9855f880-a4e8-4d3f-804c-21a19b5ac89f","children":[]},"test/order_by.test.js":{"root":"e3781dc6-7ce2-435f-862d-d1ab33e8f35c","children":[]}}}
{"processes":{"42d15934-e8f2-45a1-954f-31efa1455bf6":{"parent":"cf984c92-532d-4ae1-9559-9b4b588f05d5","externalId":"test/ignore.test.js","children":[]},"48993cf3-72fe-4040-91b5-28d8be85c30b":{"parent":"cf984c92-532d-4ae1-9559-9b4b588f05d5","externalId":"test/where.test.js","children":[]},"7f01475e-4ecf-4934-94ef-47d32f22e4cd":{"parent":"cf984c92-532d-4ae1-9559-9b4b588f05d5","externalId":"test/simple.test.js","children":[]},"c2b5c996-0b3a-4aca-b0ee-517845bda2e2":{"parent":"cf984c92-532d-4ae1-9559-9b4b588f05d5","externalId":"test/order_by.test.js","children":[]},"cdfcaa24-c93d-46da-a6b5-3e787b3a39be":{"parent":"cf984c92-532d-4ae1-9559-9b4b588f05d5","externalId":"test/hooks.test.js","children":[]},"cf984c92-532d-4ae1-9559-9b4b588f05d5":{"parent":null,"children":["42d15934-e8f2-45a1-954f-31efa1455bf6","48993cf3-72fe-4040-91b5-28d8be85c30b","7f01475e-4ecf-4934-94ef-47d32f22e4cd","c2b5c996-0b3a-4aca-b0ee-517845bda2e2","cdfcaa24-c93d-46da-a6b5-3e787b3a39be","d0d9eae7-77b6-42ef-a376-cd79dab441cb"]},"d0d9eae7-77b6-42ef-a376-cd79dab441cb":{"parent":"cf984c92-532d-4ae1-9559-9b4b588f05d5","externalId":"test/nested.test.js","children":[]}},"files":{"/Users/matteo/Repositories/platformatic/packages/sql-openapi/index.js":["42d15934-e8f2-45a1-954f-31efa1455bf6","48993cf3-72fe-4040-91b5-28d8be85c30b","7f01475e-4ecf-4934-94ef-47d32f22e4cd","c2b5c996-0b3a-4aca-b0ee-517845bda2e2","cdfcaa24-c93d-46da-a6b5-3e787b3a39be","d0d9eae7-77b6-42ef-a376-cd79dab441cb"],"/Users/matteo/Repositories/platformatic/packages/sql-openapi/lib/entity-to-routes.js":["42d15934-e8f2-45a1-954f-31efa1455bf6","48993cf3-72fe-4040-91b5-28d8be85c30b","7f01475e-4ecf-4934-94ef-47d32f22e4cd","c2b5c996-0b3a-4aca-b0ee-517845bda2e2","cdfcaa24-c93d-46da-a6b5-3e787b3a39be","d0d9eae7-77b6-42ef-a376-cd79dab441cb"]},"externalIds":{"test/ignore.test.js":{"root":"42d15934-e8f2-45a1-954f-31efa1455bf6","children":[]},"test/where.test.js":{"root":"48993cf3-72fe-4040-91b5-28d8be85c30b","children":[]},"test/simple.test.js":{"root":"7f01475e-4ecf-4934-94ef-47d32f22e4cd","children":[]},"test/order_by.test.js":{"root":"c2b5c996-0b3a-4aca-b0ee-517845bda2e2","children":[]},"test/hooks.test.js":{"root":"cdfcaa24-c93d-46da-a6b5-3e787b3a39be","children":[]},"test/nested.test.js":{"root":"d0d9eae7-77b6-42ef-a376-cd79dab441cb","children":[]}}}
'use strict'
const Swagger = require('@fastify/swagger')
const SwaggerUI = require('@fastify/swagger-ui')
const deepmerge = require('@fastify/deepmerge')({ all: true })

@@ -12,2 +13,3 @@ const camelcase = require('camelcase')

async function setupOpenAPI (app, opts) {
const prefix = opts.prefix || ''
const openapiConfig = deepmerge({

@@ -17,3 +19,4 @@ exposeRoute: true,

title: 'Platformatic DB',
description: 'Exposing a SQL database as REST'
description: 'Exposing a SQL database as REST',
version: '1.0.0'
}

@@ -36,2 +39,4 @@ }, opts)

app.register(SwaggerUI, opts)
for (const entity of Object.values(app.platformatic.entities)) {

@@ -62,3 +67,3 @@ const entitySchema = mapSQLEntityToJSONSchema(entity)

entity,
prefix: '/' + entity.pluralName
prefix: `${prefix}/${entity.pluralName}`
})

@@ -65,0 +70,0 @@ }

@@ -7,21 +7,14 @@ 'use strict'

async function entityPlugin (app, opts) {
const entity = opts.entity
const entitySchema = {
$ref: entity.name + '#'
}
const primaryKeyParams = getPrimaryKeyParams(entity)
const getEntityLinksForEntity = (app, entity) => {
const entityLinks = {}
const primaryKeyCamelcase = camelcase(entity.primaryKey)
for (const relation of entity.relations) {
const ownField = camelcase(relation.column_name)
const relatedEntity = app.platformatic.entities[camelcase(singularize(relation.foreign_table_name))]
const relatedEntityPrimaryKeyCamelcase = capitalize(camelcase(relatedEntity.primaryKey))
const getEntityById = `Get${relatedEntity.name}With${relatedEntityPrimaryKeyCamelcase}`
const relatedEntityPrimaryKeyCamelcase = camelcase(relatedEntity.primaryKey)
const relatedEntityPrimaryKeyCamelcaseCapitalized = capitalize(relatedEntityPrimaryKeyCamelcase)
const getEntityById = `Get${relatedEntity.name}By${relatedEntityPrimaryKeyCamelcaseCapitalized}`
entityLinks[getEntityById] = {
operationId: `get${relatedEntity.name}By${relatedEntityPrimaryKeyCamelcase}`,
operationId: `get${relatedEntity.name}By${relatedEntityPrimaryKeyCamelcaseCapitalized}`,
parameters: {
[primaryKeyCamelcase]: `$response.body#/${ownField}`
[relatedEntityPrimaryKeyCamelcase]: `$response.body#/${ownField}`
}

@@ -36,5 +29,5 @@ }

const relatedEntity = app.platformatic.entities[camelcase(singularize(relation.table_name))]
const getAllEntities = `GetAll${capitalize(relatedEntity.pluralName)}`
entityLinks[getAllEntities] = {
operationId: `getAll${capitalize(relatedEntity.pluralName)}`,
const getEntities = `Get${capitalize(relatedEntity.pluralName)}`
entityLinks[getEntities] = {
operationId: `get${capitalize(relatedEntity.pluralName)}`,
parameters: {

@@ -45,6 +38,27 @@ [`where.${theirField}.eq`]: `$response.body#/${ownField}`

}
return entityLinks
}
const whereArgs = Object.keys(entity.fields).sort().map((name) => {
return entity.fields[name]
}).reduce((acc, field) => {
const getFieldsForEntity = (entity) => ({
type: 'array',
items: {
type: 'string',
enum: Object.keys(entity.fields).map((field) => entity.fields[field].camelcase).sort()
}
})
async function entityPlugin (app, opts) {
const entity = opts.entity
const entitySchema = {
$ref: entity.name + '#'
}
const primaryKeyParams = getPrimaryKeyParams(entity)
const primaryKeyCamelcase = camelcase(entity.primaryKey)
const entityLinks = getEntityLinksForEntity(app, entity)
const sortedEntityFields = Object.keys(entity.fields).sort()
const whereArgs = sortedEntityFields.reduce((acc, name) => {
const field = entity.fields[name]
const baseKey = `where.${field.camelcase}.`

@@ -64,5 +78,4 @@ for (const modifier of ['eq', 'neq', 'gt', 'gte', 'lt', 'lte']) {

const orderByArgs = Object.keys(entity.fields).sort().map((name) => {
return entity.fields[name]
}).reduce((acc, field) => {
const orderByArgs = sortedEntityFields.reduce((acc, name) => {
const field = entity.fields[name]
const key = `orderby.${field.camelcase}`

@@ -79,13 +92,7 @@ acc[key] = { type: 'string', enum: ['asc', 'desc'] }

const fields = {
type: 'array',
items: {
type: 'string',
enum: Object.keys(entity.fields).map((field) => entity.fields[field].camelcase).sort()
}
}
const fields = getFieldsForEntity(entity)
app.get('/', {
schema: {
operationId: 'getAll' + entity.name,
operationId: 'get' + capitalize(entity.pluralName),
querystring: {

@@ -113,8 +120,12 @@ type: 'object',

const { limit, offset, fields } = query
// TODO computing this where clause will be slow
// refactor to use a barebone for(;;) loop
const where = Object.keys(query).reduce((acc, key) => {
if (key.indexOf('where.') === 0) {
const queryKeys = Object.keys(query)
const where = {}
const orderBy = []
for (let i = 0; i < queryKeys.length; i++) {
const key = queryKeys[i]
if (key.startsWith('where.')) {
const [, field, modifier] = key.split('.')
acc[field] = acc[field] || {}
where[field] ||= {}
let value = query[key]

@@ -128,21 +139,24 @@ if (modifier === 'in' || modifier === 'nin') {

}
acc[field][modifier] = value
return acc
}
return acc
}, {})
const orderBy = Object.keys(query).reduce((acc, key) => {
if (key.indexOf('orderby.') === 0) {
where[field][modifier] = value
} else if (key.startsWith('orderby.')) {
const [, field] = key.split('.')
acc[field] = acc[field] || {}
acc.push({ field, direction: query[key] })
orderBy[field] ||= {}
orderBy.push({ field, direction: query[key] })
}
return acc
}, [])
}
const ctx = { app: this, reply }
const res = await entity.find({ limit, offset, fields, orderBy, where, ctx })
// X-Total-Count header
if (query.totalCount) {
const totalCount = await entity.count({ where, ctx })
let totalCount
if ((((offset ?? 0) === 0) || (res.length > 0)) && ((limit === undefined) || (res.length < limit))) {
totalCount = (offset ?? 0) + res.length
} else {
totalCount = await entity.count({ where, ctx })
}
reply.header('X-Total-Count', totalCount)
}
return res

@@ -202,2 +216,133 @@ })

// For every reverse relationship we create: entity/:entity_Id/target_entity
for (const reverseRelationship of entity.reverseRelationships) {
const targetEntityName = singularize(camelcase(reverseRelationship.relation.table_name))
const targetEntity = app.platformatic.entities[targetEntityName]
const targetForeignKeyCamelcase = camelcase(reverseRelationship.relation.column_name)
const targetEntitySchema = {
$ref: targetEntity.name + '#'
}
const entityLinks = getEntityLinksForEntity(app, targetEntity)
// e.g. getQuotesForMovie
const operationId = `get${capitalize(targetEntity.pluralName)}For${capitalize(entity.singularName)}`
app.get(`/:${camelcase(entity.primaryKey)}/${targetEntity.pluralName}`, {
schema: {
operationId,
params: getPrimaryKeyParams(entity),
querystring: {
type: 'object',
properties: {
fields: getFieldsForEntity(targetEntity)
}
},
response: {
200: {
type: 'array',
items: targetEntitySchema
}
}
},
links: {
200: entityLinks
}
}, async function (request, reply) {
const ctx = { app: this, reply }
// IF we want to have HTTP/404 in case the entity does not exist
// we need to do 2 queries. One to check if the entity exists. the other to get the related entities
// Improvement: this could be also done with a single query with a join,
// check that the entity exists
const resEntity = await entity.count({
ctx,
where: {
[primaryKeyCamelcase]: {
eq: request.params[primaryKeyCamelcase]
}
}
})
if (resEntity === 0) {
return reply.callNotFound()
}
// get the related entities
const res = await targetEntity.find({
ctx,
where: {
[targetForeignKeyCamelcase]: {
eq: request.params[primaryKeyCamelcase]
}
},
fields: request.query.fields
})
if (res.length === 0) {
// This is a query on a FK, so
return []
}
return res
})
}
// For every relationship we create: entity/:entity_Id/target_entity
for (const relation of entity.relations) {
const targetEntityName = singularize(camelcase(relation.foreign_table_name))
const targetEntity = app.platformatic.entities[targetEntityName]
const targetForeignKeyCamelcase = camelcase(relation.foreign_column_name)
const targetEntitySchema = {
$ref: targetEntity.name + '#'
}
const entityLinks = getEntityLinksForEntity(app, targetEntity)
// e.g. getMovieForQuote
const operationId = `get${capitalize(targetEntity.singularName)}For${capitalize(entity.singularName)}`
app.get(`/:${camelcase(entity.primaryKey)}/${targetEntity.singularName}`, {
schema: {
operationId,
params: getPrimaryKeyParams(entity),
querystring: {
type: 'object',
properties: {
fields: getFieldsForEntity(targetEntity)
}
},
response: {
200: targetEntitySchema
}
},
links: {
200: entityLinks
}
}, async function (request, reply) {
const ctx = { app: this, reply }
// check that the entity exists
const resEntity = await entity.count({
ctx,
where: {
[primaryKeyCamelcase]: {
eq: request.params[primaryKeyCamelcase]
}
}
})
if (resEntity === 0) {
return reply.callNotFound()
}
// get the related entity
const res = await targetEntity.find({
ctx,
where: {
[targetForeignKeyCamelcase]: {
eq: request.params[primaryKeyCamelcase]
}
},
fields: request.query.fields
})
if (res.length === 0) {
return reply.callNotFound()
}
return res[0]
})
}
for (const method of ['POST', 'PUT']) {

@@ -204,0 +349,0 @@ app.route({

{
"name": "@platformatic/sql-openapi",
"version": "0.3.0",
"version": "0.4.0",
"description": "Map a SQL database to OpenAPI, for Fastify",

@@ -17,3 +17,3 @@ "main": "index.js",

"devDependencies": {
"@platformatic/sql-mapper": "0.3.0",
"@platformatic/sql-mapper": "0.4.0",
"fastify": "^4.6.0",

@@ -28,5 +28,6 @@ "mercurius": "^11.0.0",

"dependencies": {
"@platformatic/sql-json-schema-mapper": "0.3.0",
"@platformatic/sql-json-schema-mapper": "0.4.0",
"@fastify/deepmerge": "^1.1.0",
"@fastify/swagger": "^7.4.1",
"@fastify/swagger": "^8.0.0",
"@fastify/swagger-ui": "^1.0.0",
"camelcase": "^6.0.0",

@@ -33,0 +34,0 @@ "fastify-plugin": "^4.1.0",

@@ -50,2 +50,10 @@ 'use strict'

const res = await app.inject({
method: 'GET',
url: '/documentation/json'
})
equal(res.json().info.version, '1.0.0', 'GET /documentation/json info version default')
}
{
const res = await app.inject({
method: 'POST',

@@ -288,67 +296,105 @@ url: '/pages',

{
const res = await app.inject({
method: 'GET',
url: '/posts'
})
equal(res.statusCode, 200, '/posts status code')
equal(res.headers['x-total-count'], undefined, '/posts without x-total-count')
const url = '/posts'
const res = await app.inject({ method: 'GET', url })
equal(res.statusCode, 200, `${url} status code`)
equal(res.headers['x-total-count'], undefined, `${url} without x-total-count`)
same(res.json(), posts.map((p, i) => {
return { ...p, id: i + 1 + '' }
}), '/posts response')
}), `${url} response`)
}
{
const res = await app.inject({
method: 'GET',
url: '/posts?limit=3'
})
equal(res.statusCode, 200, '/posts?limit=3 status code')
const url = '/posts?limit=3'
const res = await app.inject({ method: 'GET', url })
equal(res.statusCode, 200, `${url} status code`)
equal(res.headers['x-total-count'], undefined, `${url} without x-total-count`)
same(res.json(), posts.map((p, i) => {
return { ...p, id: i + 1 + '' }
}).slice(0, 3), '/posts?limit=3 response')
}).slice(0, 3), `${url} response`)
}
{
const res = await app.inject({
method: 'GET',
url: '/posts?offset=2'
})
equal(res.statusCode, 200, '/posts?offset=2 status code')
const url = '/posts?offset=2'
const res = await app.inject({ method: 'GET', url })
equal(res.statusCode, 200, `${url} status code`)
equal(res.headers['x-total-count'], undefined, `${url} without x-total-count`)
same(res.json(), posts.map((p, i) => {
return { ...p, id: i + 1 + '' }
}).slice(2), '/posts?offset=2 response')
}).slice(2), `${url} response`)
}
{
const res = await app.inject({
method: 'GET',
url: '/posts?totalCount=true'
})
equal(res.headers['x-total-count'], posts.length, '/posts?totalCount=true with x-total-count')
equal(res.statusCode, 200, '/posts?totalCount=true status code')
const url = '/posts?limit=2&offset=1'
const res = await app.inject({ method: 'GET', url })
equal(res.statusCode, 200, `${url} status code`)
equal(res.headers['x-total-count'], undefined, `${url} without x-total-count`)
same(res.json(), posts.map((p, i) => {
return { ...p, id: i + 1 + '' }
}).slice(1, 3), `${url} response`)
}
{
const res = await app.inject({
method: 'GET',
url: '/posts?limit=2&offset=1'
})
equal(res.statusCode, 200, '/posts?limit=2&offset=1 status code')
same(res.headers['x-total-count'], undefined, '/posts?limit=2&offset=1 without x-total-count')
const url = '/posts?totalCount=true'
const res = await app.inject({ method: 'GET', url })
equal(res.statusCode, 200, `${url} status code`)
equal(res.headers['x-total-count'], posts.length, `${url} with x-total-count`)
}
{
const url = '/posts?totalCount=true&limit=3'
const res = await app.inject({ method: 'GET', url })
equal(res.statusCode, 200, `${url} status code`)
equal(res.headers['x-total-count'], posts.length, `${url} with x-total-count`)
same(res.json(), posts.map((p, i) => {
return { ...p, id: i + 1 + '' }
}).slice(1, 3), '/posts?limit=2&offset=1 response')
}).slice(0, 3), `${url} response`)
}
{
const res = await app.inject({
method: 'GET',
url: '/posts?limit=2&offset=1&totalCount=true'
})
equal(res.headers['x-total-count'], posts.length, '/posts?limit=2&offset=1&totalCount=true without x-total-count')
equal(res.statusCode, 200, 'posts status code')
const url = '/posts?totalCount=true&offset=2'
const res = await app.inject({ method: 'GET', url })
equal(res.statusCode, 200, `${url} status code`)
equal(res.headers['x-total-count'], posts.length, `${url} with x-total-count`)
same(res.json(), posts.map((p, i) => {
return { ...p, id: i + 1 + '' }
}).slice(1, 3), '/posts?limit=2&offset=1&totalCount=true response')
}).slice(2), `${url} response`)
}
{
const url = '/posts?totalCount=true&limit=2&offset=1'
const res = await app.inject({ method: 'GET', url })
equal(res.statusCode, 200, `${url} status code`)
equal(res.headers['x-total-count'], posts.length, `${url} with x-total-count`)
same(res.json(), posts.map((p, i) => {
return { ...p, id: i + 1 + '' }
}).slice(1, 3), `${url} response`)
}
{
const url = '/posts?totalCount=true&limit=2&offset=99'
const res = await app.inject({ method: 'GET', url })
equal(res.statusCode, 200, `${url} status code`)
equal(res.headers['x-total-count'], posts.length, `${url} with x-total-count`)
same(res.json(), [], `${url} response`)
}
{
const url = '/posts?totalCount=true&limit=99&offset=0'
const res = await app.inject({ method: 'GET', url })
equal(res.statusCode, 200, `${url} status code`)
equal(res.headers['x-total-count'], posts.length, `${url} with x-total-count`)
same(res.json(), posts.map((p, i) => {
return { ...p, id: i + 1 + '' }
}).slice(0, 4), `${url} response`)
}
{
const url = '/posts?totalCount=true&limit=99&offset=2'
const res = await app.inject({ method: 'GET', url })
equal(res.statusCode, 200, `${url} status code`)
equal(res.headers['x-total-count'], posts.length, `${url} with x-total-count`)
same(res.json(), posts.map((p, i) => {
return { ...p, id: i + 1 + '' }
}).slice(2, 4), `${url} response`)
}
})

@@ -483,3 +529,3 @@

test('simple db, simple rest API', async (t) => {
const { pass, teardown, matchSnapshot } = t
const { pass, teardown, matchSnapshot, equal } = t
t.snapshotFile = resolve(__dirname, 'tap-snapshots', 'simple-openapi-3.cjs')

@@ -514,2 +560,3 @@

matchSnapshot(json, 'GET /documentation/json response')
equal(json.info.version, '42.42.42', 'GET /documentation/json info version override by opts')
})

@@ -560,1 +607,61 @@

})
test('expose the api with a prefix, if defined', async (t) => {
const { pass, teardown, same, equal, matchSnapshot } = t
const app = fastify()
app.register(sqlMapper, {
...connInfo,
async onDatabaseLoad (db, sql) {
pass('onDatabaseLoad called')
await clear(db, sql)
await createBasicPages(db, sql)
}
})
app.register(sqlOpenAPI, { prefix: '/api' })
teardown(app.close.bind(app))
await app.ready()
{
const res = await app.inject({
method: 'POST',
url: '/pages',
body: {
title: 'Hello'
}
})
equal(res.statusCode, 404, 'POST /pages status code')
same(res.json(), {
message: 'Route POST:/pages not found',
error: 'Not Found',
statusCode: 404
}, 'POST /pages response')
}
{
const res = await app.inject({
method: 'POST',
url: '/api/pages',
body: {
title: 'Hello'
}
})
equal(res.statusCode, 200, 'POST /pages status code')
equal(res.headers.location, '/api/pages/1', 'POST /api/pages location')
same(res.json(), {
id: 1,
title: 'Hello'
}, 'POST /pages response')
}
// Check that the documentation is not prefixed
{
t.snapshotFile = resolve(__dirname, 'tap-snapshots', 'simple-openapi-4.cjs')
const res = await app.inject({
method: 'GET',
url: '/documentation/json'
})
const json = res.json()
matchSnapshot(json, 'GET /documentation/json response')
}
})

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc